]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
authorLinus Torvalds <torvalds@woody.osdl.org>
Tue, 12 Dec 2006 17:57:55 +0000 (09:57 -0800)
committerLinus Torvalds <torvalds@woody.osdl.org>
Tue, 12 Dec 2006 17:57:55 +0000 (09:57 -0800)
* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6:
  i2c: Fix OMAP clock prescaler to match the comment
  i2c: Refactor a kfree in i2c-dev
  i2c: Fix return value check in i2c-dev
  i2c: Enable PEC on more i2c-i801 devices
  i2c: Discard the i2c algo del_bus wrappers
  i2c: New ARM Versatile/Realview bus driver
  i2c: fix broken ds1337 initialization
  i2c: i2c-i801 documentation update
  i2c: Use the __ATTR macro where possible
  i2c: Whitespace cleanups
  i2c: Use put_user instead of copy_to_user where possible
  i2c: New Atmel AT91 bus driver
  i2c: Add support for nested i2c bus locking
  i2c: Cleanups to the i2c-nforce2 bus driver
  i2c: Add request/release_mem_region to i2c-ibm_iic bus driver
  i2c: New Philips PNX bus driver
  i2c: Delete the broken i2c-ite bus driver
  i2c: Update the list of driver IDs
  i2c: Fix documentation typos

572 files changed:
Documentation/CodingStyle
Documentation/SubmitChecklist
Documentation/accounting/getdelays.c
Documentation/dvb/cards.txt
Documentation/ioctl/ioctl-decoding.txt [new file with mode: 0644]
Documentation/networking/dccp.txt
Documentation/spi/pxa2xx
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/cafe_ccic [new file with mode: 0644]
Documentation/video4linux/zr36120.txt [deleted file]
MAINTAINERS
Makefile
arch/alpha/kernel/osf_sys.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/kernel/avr32_ksyms.c
arch/avr32/kernel/process.c
arch/avr32/kernel/setup.c
arch/avr32/lib/delay.c
arch/avr32/mach-at32ap/at32ap7000.c
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/intc.c
arch/avr32/mach-at32ap/pio.c
arch/avr32/mach-at32ap/sm.c [deleted file]
arch/frv/kernel/pm.c
arch/mips/configs/malta_defconfig
arch/mips/kernel/kspd.c
arch/mips/kernel/reset.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lasat/sysctl.c
arch/mips/lib/csum_partial_copy.c
arch/mips/mips-boards/malta/Makefile
arch/mips/mips-boards/malta/malta_setup.c
arch/mips/mm/cache.c
arch/mips/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/module_32.c
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/numa.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/cell/cbe_thermal.c
arch/powerpc/platforms/cell/pmu.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/hotplug-cpu.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dcr.S [deleted file]
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/rom.c
arch/powerpc/xmon/xmon.c
arch/ppc/kernel/pci.c
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/Makefile
arch/sh/boards/landisk/irq.c
arch/sh/boards/se/7206/irq.c
arch/sh/boards/se/7619/Makefile
arch/sh/boards/se/7619/io.c [deleted file]
arch/sh/boards/se/7619/setup.c
arch/sh/boot/Makefile
arch/sh/boot/compressed/Makefile
arch/sh/boot/compressed/head.S
arch/sh/boot/compressed/misc.c
arch/sh/configs/landisk_defconfig
arch/sh/configs/se7206_defconfig
arch/sh/configs/se7619_defconfig [new file with mode: 0644]
arch/sh/drivers/push-switch.c
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/sh2/entry.S
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh4/Makefile
arch/sh/kernel/cpu/sh4/probe.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/cpu/sh4a/Makefile [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh73180.c [moved from arch/sh/kernel/cpu/sh4/clock-sh73180.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/clock-sh7343.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/clock-sh7770.c [moved from arch/sh/kernel/cpu/sh4/clock-sh7770.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/clock-sh7780.c [moved from arch/sh/kernel/cpu/sh4/clock-sh7780.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/setup-sh73180.c [moved from arch/sh/kernel/cpu/sh4/setup-sh73180.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/setup-sh7343.c [moved from arch/sh/kernel/cpu/sh4/setup-sh7343.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/setup-sh7722.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7770.c [moved from arch/sh/kernel/cpu/sh4/setup-sh7770.c with 100% similarity]
arch/sh/kernel/cpu/sh4a/setup-sh7780.c [moved from arch/sh/kernel/cpu/sh4/setup-sh7780.c with 100% similarity]
arch/sh/kernel/early_printk.c
arch/sh/kernel/entry-common.S
arch/sh/kernel/head.S
arch/sh/kernel/process.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/signal.c
arch/sh/kernel/sys_sh.c
arch/sh/kernel/traps.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/mm/Kconfig
arch/sh/mm/cache-sh4.c
arch/sh/mm/init.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/of_device.c
arch/sparc/kernel/ptrace.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/mm/io-unit.c
arch/sparc64/Kconfig
arch/sparc64/Kconfig.debug
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/chmc.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/isa.c
arch/sparc64/kernel/kprobes.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/stacktrace.c [new file with mode: 0644]
arch/sparc64/kernel/sun4v_ivec.S
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/unaligned.c
arch/sparc64/kernel/visemul.c
arch/sparc64/mm/ultra.S
arch/x86_64/Kconfig
arch/x86_64/kernel/vsyscall.c
arch/xtensa/Kconfig
arch/xtensa/Makefile
arch/xtensa/boot/boot-elf/bootstrap.S
arch/xtensa/boot/boot-redboot/bootstrap.S
arch/xtensa/configs/iss_defconfig
arch/xtensa/kernel/align.S
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/pci-dma.c
arch/xtensa/kernel/process.c
arch/xtensa/kernel/ptrace.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/syscall.c [new file with mode: 0644]
arch/xtensa/kernel/syscalls.c [deleted file]
arch/xtensa/kernel/syscalls.h [deleted file]
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/lib/checksum.S
arch/xtensa/lib/memcopy.S
arch/xtensa/lib/memset.S
arch/xtensa/lib/strncpy_user.S
arch/xtensa/lib/strnlen_user.S
arch/xtensa/lib/usercopy.S
arch/xtensa/mm/fault.c
arch/xtensa/mm/init.c
arch/xtensa/mm/misc.S
arch/xtensa/mm/tlb.c
arch/xtensa/platform-iss/console.c
arch/xtensa/platform-iss/network.c
block/ll_rw_blk.c
block/scsi_ioctl.c
crypto/sha512.c
drivers/Kconfig
drivers/Makefile
drivers/atm/.gitignore
drivers/char/ipmi/ipmi_bt_sm.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_poweroff.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/char/mem.c
drivers/char/random.c
drivers/clocksource/acpi_pm.c
drivers/crypto/Kconfig
drivers/ide/ide-cd.c
drivers/ide/ide-probe.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/piix.c
drivers/ide/setup-pci.c
drivers/input/touchscreen/Kconfig
drivers/isdn/hisax/Kconfig
drivers/kvm/Kconfig [new file with mode: 0644]
drivers/kvm/Makefile [new file with mode: 0644]
drivers/kvm/kvm.h [new file with mode: 0644]
drivers/kvm/kvm_main.c [new file with mode: 0644]
drivers/kvm/kvm_svm.h [new file with mode: 0644]
drivers/kvm/kvm_vmx.h [new file with mode: 0644]
drivers/kvm/mmu.c [new file with mode: 0644]
drivers/kvm/paging_tmpl.h [new file with mode: 0644]
drivers/kvm/segment_descriptor.h [new file with mode: 0644]
drivers/kvm/svm.c [new file with mode: 0644]
drivers/kvm/svm.h [new file with mode: 0644]
drivers/kvm/vmx.c [new file with mode: 0644]
drivers/kvm/vmx.h [new file with mode: 0644]
drivers/kvm/x86_emulate.c [new file with mode: 0644]
drivers/kvm/x86_emulate.h [new file with mode: 0644]
drivers/md/Kconfig
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/media/Kconfig
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_i2c.c
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb-mc.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/ttusb2.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/ttusb2.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb/umt-010.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dib7000m.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib7000m.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib7000p.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib7000p.h [new file with mode: 0644]
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lg_h06xf.h [deleted file]
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/lgdt330x_priv.h
drivers/media/dvb/frontends/lgh06xf.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgh06xf.h [new file with mode: 0644]
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/tda1004x.h
drivers/media/dvb/frontends/tda8083.c
drivers/media/dvb/frontends/tda826x.c
drivers/media/dvb/frontends/tua6100.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110_ir.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/cafe_ccic-regs.h [new file with mode: 0644]
drivers/media/video/cafe_ccic.c [new file with mode: 0644]
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/mxb.c
drivers/media/video/ov7670.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/stv680.c
drivers/media/video/tda9887.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tveeprom.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvision/Kconfig [new file with mode: 0644]
drivers/media/video/usbvision/Makefile [new file with mode: 0644]
drivers/media/video/usbvision/usbvision-cards.c [new file with mode: 0644]
drivers/media/video/usbvision/usbvision-core.c [new file with mode: 0644]
drivers/media/video/usbvision/usbvision-i2c.c [new file with mode: 0644]
drivers/media/video/usbvision/usbvision-video.c [new file with mode: 0644]
drivers/media/video/usbvision/usbvision.h [new file with mode: 0644]
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/videodev.c
drivers/media/video/vivi.c
drivers/media/video/zr36120.c [deleted file]
drivers/media/video/zr36120.h [deleted file]
drivers/media/video/zr36120_i2c.c [deleted file]
drivers/media/video/zr36120_mem.c [deleted file]
drivers/media/video/zr36120_mem.h [deleted file]
drivers/mmc/at91_mci.c
drivers/mmc/mmc_queue.c
drivers/mmc/sdhci.c
drivers/net/8139too.c
drivers/net/Kconfig
drivers/net/chelsio/cxgb2.c
drivers/net/chelsio/sge.c
drivers/net/chelsio/sge.h
drivers/net/hamradio/baycom_epp.c
drivers/net/macb.c
drivers/net/macb.h
drivers/net/myri10ge/myri10ge.c
drivers/net/smc91x.h
drivers/net/ucc_geth.c
drivers/net/wan/Kconfig
drivers/parport/Kconfig
drivers/pci/hotplug/Kconfig
drivers/ps3/Makefile
drivers/ps3/vuart.c [new file with mode: 0644]
drivers/ps3/vuart.h [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at91rm9200.c [moved from drivers/rtc/rtc-at91.c with 100% similarity]
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-lib.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-x1205.c
drivers/serial/Kconfig
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
drivers/spi/pxa2xx_spi.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/gxt4500.c [new file with mode: 0644]
fs/buffer.c
fs/cifs/file.c
fs/compat.c
fs/direct-io.c
fs/exec.c
fs/fcntl.c
fs/file.c
fs/jbd/transaction.c
fs/jfs/jfs_filsys.h
fs/open.c
fs/proc/base.c
fs/proc/proc_misc.c
fs/select.c
fs/xfs/linux-2.6/xfs_aops.c
include/asm-arm/arch-pxa/pxa2xx_spi.h
include/asm-avr32/arch-at32ap/at32ap7000.h [new file with mode: 0644]
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/arch-at32ap/portmux.h
include/asm-avr32/dma-mapping.h
include/asm-generic/vmlinux.lds.h
include/asm-i386/topology.h
include/asm-ia64/topology.h
include/asm-mips/compat.h
include/asm-mips/mach-ip27/irq.h
include/asm-mips/mach-ip27/topology.h
include/asm-mips/pci.h
include/asm-mips/ptrace.h
include/asm-mips/sn/arch.h
include/asm-mips/sn/klconfig.h
include/asm-mips/system.h
include/asm-powerpc/Kbuild
include/asm-powerpc/bitops.h
include/asm-powerpc/bug.h
include/asm-powerpc/cputable.h
include/asm-powerpc/dcr-native.h
include/asm-powerpc/dcr.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/module.h
include/asm-powerpc/pci-bridge.h
include/asm-powerpc/pci.h
include/asm-powerpc/reg.h
include/asm-powerpc/rtas.h
include/asm-powerpc/topology.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/pci.h
include/asm-ppc/reg_booke.h
include/asm-sh/atomic-irq.h [new file with mode: 0644]
include/asm-sh/atomic-llsc.h [new file with mode: 0644]
include/asm-sh/atomic.h
include/asm-sh/bug.h
include/asm-sh/bugs.h
include/asm-sh/checksum.h
include/asm-sh/cpu-sh4/cache.h
include/asm-sh/cpu-sh4/freq.h
include/asm-sh/dma-mapping.h
include/asm-sh/irq.h
include/asm-sh/pgtable.h
include/asm-sh/processor.h
include/asm-sh/push-switch.h
include/asm-sparc64/dma.h
include/asm-sparc64/irqflags.h [new file with mode: 0644]
include/asm-sparc64/kprobes.h
include/asm-sparc64/rwsem.h
include/asm-sparc64/system.h
include/asm-sparc64/ttable.h
include/asm-x86_64/topology.h
include/asm-xtensa/asmmacro.h [new file with mode: 0644]
include/asm-xtensa/bug.h
include/asm-xtensa/byteorder.h
include/asm-xtensa/cache.h
include/asm-xtensa/cacheasm.h [new file with mode: 0644]
include/asm-xtensa/cacheflush.h
include/asm-xtensa/checksum.h
include/asm-xtensa/coprocessor.h
include/asm-xtensa/dma.h
include/asm-xtensa/elf.h
include/asm-xtensa/fcntl.h
include/asm-xtensa/fixmap.h [deleted file]
include/asm-xtensa/io.h
include/asm-xtensa/irq.h
include/asm-xtensa/irq_regs.h [new file with mode: 0644]
include/asm-xtensa/mmu_context.h
include/asm-xtensa/page.h
include/asm-xtensa/param.h
include/asm-xtensa/pgtable.h
include/asm-xtensa/platform-iss/hardware.h
include/asm-xtensa/platform-iss/simcall.h [new file with mode: 0644]
include/asm-xtensa/posix_types.h
include/asm-xtensa/processor.h
include/asm-xtensa/ptrace.h
include/asm-xtensa/regs.h [new file with mode: 0644]
include/asm-xtensa/sembuf.h
include/asm-xtensa/shmbuf.h
include/asm-xtensa/stat.h
include/asm-xtensa/syscall.h [new file with mode: 0644]
include/asm-xtensa/system.h
include/asm-xtensa/timex.h
include/asm-xtensa/tlbflush.h
include/asm-xtensa/unistd.h
include/asm-xtensa/variant-fsf/core.h [new file with mode: 0644]
include/asm-xtensa/variant-fsf/tie.h [new file with mode: 0644]
include/asm-xtensa/xtensa/cacheasm.h [deleted file]
include/asm-xtensa/xtensa/cacheattrasm.h [deleted file]
include/asm-xtensa/xtensa/config-linux_be/core.h [deleted file]
include/asm-xtensa/xtensa/config-linux_be/defs.h [deleted file]
include/asm-xtensa/xtensa/config-linux_be/specreg.h [deleted file]
include/asm-xtensa/xtensa/config-linux_be/system.h [deleted file]
include/asm-xtensa/xtensa/config-linux_be/tie.h [deleted file]
include/asm-xtensa/xtensa/coreasm.h [deleted file]
include/asm-xtensa/xtensa/corebits.h [deleted file]
include/asm-xtensa/xtensa/hal.h [deleted file]
include/asm-xtensa/xtensa/simcall.h [deleted file]
include/asm-xtensa/xtensa/xt2000-uart.h [deleted file]
include/asm-xtensa/xtensa/xt2000.h [deleted file]
include/asm-xtensa/xtensa/xtboard.h [deleted file]
include/linux/Kbuild
include/linux/blkdev.h
include/linux/clocksource.h
include/linux/dccp.h
include/linux/file.h
include/linux/freezer.h
include/linux/fsl_devices.h
include/linux/futex.h
include/linux/i2c-id.h
include/linux/ide.h
include/linux/init.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/kernel.h
include/linux/kvm.h [new file with mode: 0644]
include/linux/raid/raid5.h
include/linux/rtc.h
include/linux/sched.h
include/linux/seqlock.h
include/linux/sysctl.h
include/linux/task_io_accounting.h [new file with mode: 0644]
include/linux/task_io_accounting_ops.h [new file with mode: 0644]
include/linux/taskstats.h
include/linux/tfrc.h
include/linux/timer.h
include/linux/topology.h
include/linux/videodev2.h
include/media/ir-common.h
include/media/saa7146.h
include/media/tuner-types.h
include/media/tuner.h
include/media/tveeprom.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/net/ax25.h
include/net/ip.h
include/net/sctp/sctp.h
init/Kconfig
init/initramfs.c
init/main.c
init/version.c
kernel/exit.c
kernel/fork.c
kernel/sched.c
kernel/sysctl.c
kernel/time/clocksource.c
kernel/timer.c
kernel/tsacct.c
lib/Kconfig.debug
lib/bitrev.c
mm/filemap.c
mm/memory.c
mm/page-writeback.c
mm/readahead.c
mm/slab.c
mm/truncate.c
net/ax25/ax25_addr.c
net/core/netpoll.c
net/dccp/ackvec.c
net/dccp/ccid.h
net/dccp/ccids/ccid2.c
net/dccp/ccids/ccid3.c
net/dccp/ccids/ccid3.h
net/dccp/ccids/lib/packet_history.c
net/dccp/ccids/lib/packet_history.h
net/dccp/ccids/lib/tfrc.h
net/dccp/ccids/lib/tfrc_equation.c
net/dccp/dccp.h
net/dccp/feat.c
net/dccp/input.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/minisocks.c
net/dccp/options.c
net/dccp/output.c
net/dccp/proto.c
net/dccp/timer.c
net/decnet/dn_dev.c
net/decnet/sysctl_net_decnet.c
net/ieee80211/softmac/ieee80211softmac_assoc.c
net/ipv4/devinet.c
net/ipv4/ipvs/ip_vs_sync.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ndisc.c
scripts/Kbuild.include
security/selinux/hooks.c

index 29c18966b0502c3489e1058bd361db50a6c07686..0ad6dcb5d45ffd0f9f7e5ae1d64044afa51b1b8b 100644 (file)
@@ -35,12 +35,37 @@ In short, 8-char indents make things easier to read, and have the added
 benefit of warning you when you're nesting your functions too deep.
 Heed that warning.
 
+The preferred way to ease multiple indentation levels in a switch statement is
+to align the "switch" and its subordinate "case" labels in the same column
+instead of "double-indenting" the "case" labels.  E.g.:
+
+       switch (suffix) {
+       case 'G':
+       case 'g':
+               mem <<= 30;
+               break;
+       case 'M':
+       case 'm':
+               mem <<= 20;
+               break;
+       case 'K':
+       case 'k':
+               mem <<= 10;
+               /* fall through */
+       default:
+               break;
+       }
+
+
 Don't put multiple statements on a single line unless you have
 something to hide:
 
        if (condition) do_this;
          do_something_everytime;
 
+Don't put multiple assignments on a single line either.  Kernel coding style
+is super simple.  Avoid tricky expressions.
+
 Outside of comments, documentation and except in Kconfig, spaces are never
 used for indentation, and the above example is deliberately broken.
 
@@ -69,7 +94,7 @@ void fun(int a, int b, int c)
                next_statement;
 }
 
-               Chapter 3: Placing Braces
+               Chapter 3: Placing Braces and Spaces
 
 The other issue that always comes up in C styling is the placement of
 braces.  Unlike the indent size, there are few technical reasons to
@@ -81,6 +106,20 @@ brace last on the line, and put the closing brace first, thusly:
                we do y
        }
 
+This applies to all non-function statement blocks (if, switch, for,
+while, do).  E.g.:
+
+       switch (action) {
+       case KOBJ_ADD:
+               return "add";
+       case KOBJ_REMOVE:
+               return "remove";
+       case KOBJ_CHANGE:
+               return "change";
+       default:
+               return NULL;
+       }
+
 However, there is one special case, namely functions: they have the
 opening brace at the beginning of the next line, thus:
 
@@ -121,6 +160,49 @@ supply of new-lines on your screen is not a renewable resource (think
 25-line terminal screens here), you have more empty lines to put
 comments on.
 
+               3.1:  Spaces
+
+Linux kernel style for use of spaces depends (mostly) on
+function-versus-keyword usage.  Use a space after (most) keywords.  The
+notable exceptions are sizeof, typeof, alignof, and __attribute__, which look
+somewhat like functions (and are usually used with parentheses in Linux,
+although they are not required in the language, as in: "sizeof info" after
+"struct fileinfo info;" is declared).
+
+So use a space after these keywords:
+       if, switch, case, for, do, while
+but not with sizeof, typeof, alignof, or __attribute__.  E.g.,
+       s = sizeof(struct file);
+
+Do not add spaces around (inside) parenthesized expressions.  This example is
+*bad*:
+
+       s = sizeof( struct file );
+
+When declaring pointer data or a function that returns a pointer type, the
+preferred use of '*' is adjacent to the data name or function name and not
+adjacent to the type name.  Examples:
+
+       char *linux_banner;
+       unsigned long long memparse(char *ptr, char **retptr);
+       char *match_strdup(substring_t *s);
+
+Use one space around (on each side of) most binary and ternary operators,
+such as any of these:
+
+       =  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :
+
+but no space after unary operators:
+       &  *  +  -  ~  !  sizeof  typeof  alignof  __attribute__  defined
+
+no space before the postfix increment & decrement unary operators:
+       ++  --
+
+no space after the prefix increment & decrement unary operators:
+       ++  --
+
+and no space around the '.' and "->" structure member operators.
+
 
                Chapter 4: Naming
 
@@ -152,7 +234,7 @@ variable that is used to hold a temporary value.
 
 If you are afraid to mix up your local variable names, you have another
 problem, which is called the function-growth-hormone-imbalance syndrome.
-See next chapter.
+See chapter 6 (Functions).
 
 
                Chapter 5: Typedefs
@@ -258,6 +340,20 @@ generally easily keep track of about 7 different things, anything more
 and it gets confused.  You know you're brilliant, but maybe you'd like
 to understand what you did 2 weeks from now.
 
+In source files, separate functions with one blank line.  If the function is
+exported, the EXPORT* macro for it should follow immediately after the closing
+function brace line.  E.g.:
+
+int system_is_up(void)
+{
+       return system_state == SYSTEM_RUNNING;
+}
+EXPORT_SYMBOL(system_is_up);
+
+In function prototypes, include parameter names with their data types.
+Although this is not required by the C language, it is preferred in Linux
+because it is a simple way to add valuable information for the reader.
+
 
                Chapter 7: Centralized exiting of functions
 
@@ -306,16 +402,36 @@ time to explain badly written code.
 Generally, you want your comments to tell WHAT your code does, not HOW.
 Also, try to avoid putting comments inside a function body: if the
 function is so complex that you need to separately comment parts of it,
-you should probably go back to chapter 5 for a while.  You can make
+you should probably go back to chapter 6 for a while.  You can make
 small comments to note or warn about something particularly clever (or
 ugly), but try to avoid excess.  Instead, put the comments at the head
 of the function, telling people what it does, and possibly WHY it does
 it.
 
-When commenting the kernel API functions, please use the kerneldoc format.
+When commenting the kernel API functions, please use the kernel-doc format.
 See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc
 for details.
 
+Linux style for comments is the C89 "/* ... */" style.
+Don't use C99-style "// ..." comments.
+
+The preferred style for long (multi-line) comments is:
+
+       /*
+        * This is the preferred style for multi-line
+        * comments in the Linux kernel source code.
+        * Please use it consistently.
+        *
+        * Description:  A column of asterisks on the left side,
+        * with beginning and ending almost-blank lines.
+        */
+
+It's also important to comment data, whether they are basic types or derived
+types.  To this end, use just one data declaration per line (no commas for
+multiple data declarations).  This leaves you room for a small comment on each
+item, explaining its use.
+
+
                Chapter 9: You've made a mess of it
 
 That's OK, we all do.  You've probably been told by your long-time Unix
@@ -591,4 +707,4 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
 http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
 
 --
-Last updated on 30 April 2006.
+Last updated on 2006-December-06.
index 7ac61f60037af81905aad58a39d70152f333eb82..2270efa101530f8f1de58e951d9c7b4a1f6969d0 100644 (file)
@@ -66,3 +66,9 @@ kernel patches.
     See Documentation/ABI/README for more information.
 
 20: Check that it all passes `make headers_check'.
+
+21: Has been checked with injection of at least slab and page-allocation
+    fauilures.  See Documentation/fault-injection/.
+
+    If the new code is substantial, addition of subsystem-specific fault
+    injection might be appropriate.
index bf2b0e2f87e1acb3baef885d5e5ffcffcccb6cea..e9126e794ed7c04c19c42fb318dd36295d8806da 100644 (file)
@@ -7,6 +7,8 @@
  * Copyright (C) Balbir Singh, IBM Corp. 2006
  * Copyright (c) Jay Lan, SGI. 2006
  *
+ * Compile with
+ *     gcc -I/usr/src/linux/include getdelays.c -o getdelays
  */
 
 #include <stdio.h>
 #define NLA_DATA(na)           ((void *)((char*)(na) + NLA_HDRLEN))
 #define NLA_PAYLOAD(len)       (len - NLA_HDRLEN)
 
-#define err(code, fmt, arg...) do { printf(fmt, ##arg); exit(code); } while (0)
-int done = 0;
-int rcvbufsz=0;
-
-    char name[100];
-int dbg=0, print_delays=0;
+#define err(code, fmt, arg...)                 \
+       do {                                    \
+               fprintf(stderr, fmt, ##arg);    \
+               exit(code);                     \
+       } while (0)
+
+int done;
+int rcvbufsz;
+char name[100];
+int dbg;
+int print_delays;
+int print_io_accounting;
 __u64 stime, utime;
+
 #define PRINTF(fmt, arg...) {                  \
            if (dbg) {                          \
                printf(fmt, ##arg);             \
@@ -78,8 +87,9 @@ static int create_nl_socket(int protocol)
        if (rcvbufsz)
                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
                                &rcvbufsz, sizeof(rcvbufsz)) < 0) {
-                       printf("Unable to set socket rcv buf size to %d\n",
-                              rcvbufsz);
+                       fprintf(stderr, "Unable to set socket rcv buf size "
+                                       "to %d\n",
+                               rcvbufsz);
                        return -1;
                }
 
@@ -186,6 +196,15 @@ void print_delayacct(struct taskstats *t)
               "count", "delay total", t->swapin_count, t->swapin_delay_total);
 }
 
+void print_ioacct(struct taskstats *t)
+{
+       printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
+               t->ac_comm,
+               (unsigned long long)t->read_bytes,
+               (unsigned long long)t->write_bytes,
+               (unsigned long long)t->cancelled_write_bytes);
+}
+
 int main(int argc, char *argv[])
 {
        int c, rc, rep_len, aggr_len, len2, cmd_type;
@@ -208,7 +227,7 @@ int main(int argc, char *argv[])
        struct msgtemplate msg;
 
        while (1) {
-               c = getopt(argc, argv, "dw:r:m:t:p:v:l");
+               c = getopt(argc, argv, "diw:r:m:t:p:v:l");
                if (c < 0)
                        break;
 
@@ -217,6 +236,10 @@ int main(int argc, char *argv[])
                        printf("print delayacct stats ON\n");
                        print_delays = 1;
                        break;
+               case 'i':
+                       printf("printing IO accounting\n");
+                       print_io_accounting = 1;
+                       break;
                case 'w':
                        strncpy(logfile, optarg, MAX_FILENAME);
                        printf("write to file %s\n", logfile);
@@ -238,14 +261,12 @@ int main(int argc, char *argv[])
                        if (!tid)
                                err(1, "Invalid tgid\n");
                        cmd_type = TASKSTATS_CMD_ATTR_TGID;
-                       print_delays = 1;
                        break;
                case 'p':
                        tid = atoi(optarg);
                        if (!tid)
                                err(1, "Invalid pid\n");
                        cmd_type = TASKSTATS_CMD_ATTR_PID;
-                       print_delays = 1;
                        break;
                case 'v':
                        printf("debug on\n");
@@ -277,7 +298,7 @@ int main(int argc, char *argv[])
        mypid = getpid();
        id = get_family_id(nl_sd);
        if (!id) {
-               printf("Error getting family id, errno %d", errno);
+               fprintf(stderr, "Error getting family id, errno %d\n", errno);
                goto err;
        }
        PRINTF("family id %d\n", id);
@@ -288,7 +309,7 @@ int main(int argc, char *argv[])
                              &cpumask, strlen(cpumask) + 1);
                PRINTF("Sent register cpumask, retval %d\n", rc);
                if (rc < 0) {
-                       printf("error sending register cpumask\n");
+                       fprintf(stderr, "error sending register cpumask\n");
                        goto err;
                }
        }
@@ -298,7 +319,7 @@ int main(int argc, char *argv[])
                              cmd_type, &tid, sizeof(__u32));
                PRINTF("Sent pid/tgid, retval %d\n", rc);
                if (rc < 0) {
-                       printf("error sending tid/tgid cmd\n");
+                       fprintf(stderr, "error sending tid/tgid cmd\n");
                        goto done;
                }
        }
@@ -310,13 +331,15 @@ int main(int argc, char *argv[])
                PRINTF("received %d bytes\n", rep_len);
 
                if (rep_len < 0) {
-                       printf("nonfatal reply error: errno %d\n", errno);
+                       fprintf(stderr, "nonfatal reply error: errno %d\n",
+                               errno);
                        continue;
                }
                if (msg.n.nlmsg_type == NLMSG_ERROR ||
                    !NLMSG_OK((&msg.n), rep_len)) {
                        struct nlmsgerr *err = NLMSG_DATA(&msg);
-                       printf("fatal reply error,  errno %d\n", err->error);
+                       fprintf(stderr, "fatal reply error,  errno %d\n",
+                               err->error);
                        goto done;
                }
 
@@ -356,6 +379,8 @@ int main(int argc, char *argv[])
                                                count++;
                                                if (print_delays)
                                                        print_delayacct((struct taskstats *) NLA_DATA(na));
+                                               if (print_io_accounting)
+                                                       print_ioacct((struct taskstats *) NLA_DATA(na));
                                                if (fd) {
                                                        if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
                                                                err(1,"write error\n");
@@ -365,7 +390,9 @@ int main(int argc, char *argv[])
                                                        goto done;
                                                break;
                                        default:
-                                               printf("Unknown nested nla_type %d\n", na->nla_type);
+                                               fprintf(stderr, "Unknown nested"
+                                                       " nla_type %d\n",
+                                                       na->nla_type);
                                                break;
                                        }
                                        len2 += NLA_ALIGN(na->nla_len);
@@ -374,7 +401,8 @@ int main(int argc, char *argv[])
                                break;
 
                        default:
-                               printf("Unknown nla_type %d\n", na->nla_type);
+                               fprintf(stderr, "Unknown nla_type %d\n",
+                                       na->nla_type);
                                break;
                        }
                        na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
index ca58e339d85fe2e1fa036e89719b40c462d3d0d6..cc09187a5db75652ad36d3f750ca87f4f3b6ebda 100644 (file)
@@ -22,10 +22,10 @@ o Frontends drivers:
    - ves1x93           : Alps BSRV2 (ves1893 demodulator) and dbox2 (ves1993)
    - cx24110           : Conexant HM1221/HM1811 (cx24110 or cx24106 demod, cx24108 PLL)
    - grundig_29504-491 : Grundig 29504-491 (Philips TDA8083 demodulator), tsa5522 PLL
-   - mt312             : Zarlink mt312 or Mitel vp310 demodulator, sl1935 or tsa5059 PLL
+   - mt312             : Zarlink mt312 or Mitel vp310 demodulator, sl1935 or tsa5059 PLLi, Technisat Sky2Pc with bios Rev. 2.3
    - stv0299           : Alps BSRU6 (tsa5059 PLL), LG TDQB-S00x (tsa5059 PLL),
                          LG TDQF-S001F (sl1935 PLL), Philips SU1278 (tua6100 PLL),
-                         Philips SU1278SH (tsa5059 PLL), Samsung TBMU24112IMB
+                         Philips SU1278SH (tsa5059 PLL), Samsung TBMU24112IMB, Technisat Sky2Pc with bios Rev. 2.6
   DVB-C:
    - ves1820           : various (ves1820 demodulator, sp5659c or spXXXX PLL)
    - at76c651          : Atmel AT76c651(B) with DAT7021 PLL
diff --git a/Documentation/ioctl/ioctl-decoding.txt b/Documentation/ioctl/ioctl-decoding.txt
new file mode 100644 (file)
index 0000000..bfdf7f3
--- /dev/null
@@ -0,0 +1,24 @@
+To decode a hex IOCTL code:
+
+Most architecures use this generic format, but check
+include/ARCH/ioctl.h for specifics, e.g. powerpc
+uses 3 bits to encode read/write and 13 bits for size.
+
+ bits    meaning
+ 31-30 00 - no parameters: uses _IO macro
+       10 - read: _IOR
+       01 - write: _IOW
+       11 - read/write: _IOWR
+
+ 29-16 size of arguments
+
+ 15-8  ascii character supposedly
+       unique to each driver
+
+ 7-0   function #
+
+
+ So for example 0x82187201 is a read with arg length of 0x218,
+character 'r' function 1. Grepping the source reveals this is:
+
+#define VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct dirent [2])
index dda15886bcb51045ad5168dcafb8e0e5048c6301..387482e46c474ed49bcc31081c39528ad1fdbfa4 100644 (file)
@@ -19,7 +19,8 @@ for real time and multimedia traffic.
 
 It has a base protocol and pluggable congestion control IDs (CCIDs).
 
-It is at experimental RFC status and the homepage for DCCP as a protocol is at:
+It is at proposed standard RFC status and the homepage for DCCP as a protocol
+is at:
        http://www.read.cs.ucla.edu/dccp/
 
 Missing features
@@ -34,9 +35,6 @@ The known bugs are at:
 Socket options
 ==============
 
-DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
-calculations.
-
 DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
 service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
 the socket will fall back to 0 (which means that no meaningful service code
index a1e0ee20f595cc5cf6fb94d5fd4b7caf1430e7f2..f9717fe9bd85296c8ae892003f70f013262a5fb1 100644 (file)
@@ -102,7 +102,7 @@ struct pxa2xx_spi_chip {
        u8 tx_threshold;
        u8 rx_threshold;
        u8 dma_burst_size;
-       u32 timeout_microsecs;
+       u32 timeout;
        u8 enable_loopback;
        void (*cs_control)(u32 command);
 };
@@ -121,7 +121,7 @@ the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
 to determine the correct value. An SSP configured for byte-wide transfers would
 use a value of 8.
 
-The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
+The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
 trailing bytes in the SSP receiver fifo.  The correct value for this field is
 dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
 slave device.  Please note that the PXA2xx SSP 1 does not support trailing byte
@@ -162,18 +162,18 @@ static void cs8405a_cs_control(u32 command)
 }
 
 static struct pxa2xx_spi_chip cs8415a_chip_info = {
-       .tx_threshold = 12, /* SSP hardward FIFO threshold */
-       .rx_threshold = 4, /* SSP hardward FIFO threshold */
+       .tx_threshold = 8, /* SSP hardward FIFO threshold */
+       .rx_threshold = 8, /* SSP hardward FIFO threshold */
        .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
-       .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
+       .timeout = 235, /* See Intel documentation */
        .cs_control = cs8415a_cs_control, /* Use external chip select */
 };
 
 static struct pxa2xx_spi_chip cs8405a_chip_info = {
-       .tx_threshold = 12, /* SSP hardward FIFO threshold */
-       .rx_threshold = 4, /* SSP hardward FIFO threshold */
+       .tx_threshold = 8, /* SSP hardward FIFO threshold */
+       .rx_threshold = 8, /* SSP hardward FIFO threshold */
        .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
-       .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
+       .timeout = 235, /* See Intel documentation */
        .cs_control = cs8405a_cs_control, /* Use external chip select */
 };
 
index 8755b3e7b09e500446d99800e8abc90df96c2b85..62e32b49cec966006d66f8d8ef0e703d81b57c18 100644 (file)
@@ -43,7 +43,7 @@
  42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025,1822:0019]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1,12ab:2300]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
- 45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
+ 45 -> KWorld HardwareMpegTV XPert                         [17de:0840,1421:0305]
  46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
  47 -> pcHDTV HD5500 HDTV                                  [7063:5500]
  48 -> Kworld MCE 200 Deluxe                               [17de:0841]
index 53ce6a39083c22036bd7b52678da54cbc4a27d20..f6201cc37ec5fb608418b2e8b0cf64aeb33911ad 100644 (file)
@@ -76,7 +76,7 @@
  75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
  76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
  77 -> Pinnacle PCTV 40i/50i/110i (saa7133)     [11bd:002e]
- 78 -> ASUSTeK P7131 Dual                       [1043:4862]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4876]
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
@@ -99,3 +99,8 @@
  98 -> Proteus Pro 2309                         [0919:2003]
  99 -> AVerMedia TV Hybrid A16AR                [1461:2c00]
 100 -> Asus Europa2 OEM                         [1043:4860]
+101 -> Pinnacle PCTV 310i                       [11bd:002f]
+102 -> Avermedia AVerTV Studio 507              [1461:9715]
+103 -> Compro Videomate DVB-T200A
+104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid     [0070:6701]
+105 -> Terratec Cinergy HT PCMCIA               [153b:1172]
diff --git a/Documentation/video4linux/cafe_ccic b/Documentation/video4linux/cafe_ccic
new file mode 100644 (file)
index 0000000..8882102
--- /dev/null
@@ -0,0 +1,54 @@
+"cafe_ccic" is a driver for the Marvell 88ALP01 "cafe" CMOS camera
+controller.  This is the controller found in first-generation OLPC systems,
+and this driver was written with support from the OLPC project.
+
+Current status: the core driver works.  It can generate data in YUV422,
+RGB565, and RGB444 formats.  (Anybody looking at the code will see RGB32 as
+well, but that is a debugging aid which will be removed shortly).  VGA and
+QVGA modes work; CIF is there but the colors remain funky.  Only the OV7670
+sensor is known to work with this controller at this time.
+
+To try it out: either of these commands will work:
+
+     mplayer tv:// -tv driver=v4l2:width=640:height=480 -nosound
+     mplayer tv:// -tv driver=v4l2:width=640:height=480:outfmt=bgr16 -nosound
+
+The "xawtv" utility also works; gqcam does not, for unknown reasons.
+
+There are a few load-time options, most of which can be changed after
+loading via sysfs as well:
+
+ - alloc_bufs_at_load:  Normally, the driver will not allocate any DMA
+   buffers until the time comes to transfer data.  If this option is set,
+   then worst-case-sized buffers will be allocated at module load time.
+   This option nails down the memory for the life of the module, but
+   perhaps decreases the chances of an allocation failure later on.
+
+ - dma_buf_size: The size of DMA buffers to allocate.  Note that this
+   option is only consulted for load-time allocation; when buffers are
+   allocated at run time, they will be sized appropriately for the current
+   camera settings.
+
+ - n_dma_bufs: The controller can cycle through either two or three DMA
+   buffers.  Normally, the driver tries to use three buffers; on faster
+   systems, however, it will work well with only two.
+
+ - min_buffers: The minimum number of streaming I/O buffers that the driver
+   will consent to work with.  Default is one, but, on slower systems,
+   better behavior with mplayer can be achieved by setting to a higher
+   value (like six).
+
+ - max_buffers: The maximum number of streaming I/O buffers; default is
+   ten.  That number was carefully picked out of a hat and should not be
+   assumed to actually mean much of anything.
+
+ - flip: If this boolean parameter is set, the sensor will be instructed to
+   invert the video image.  Whether it makes sense is determined by how
+   your particular camera is mounted.
+
+Work is ongoing with this driver, stay tuned.
+
+jon
+
+Jonathan Corbet
+corbet@lwn.net
diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt
deleted file mode 100644 (file)
index 1a1c2d0..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-Driver for Trust Computer Products Framegrabber, version 0.6.1
------- --- ----- -------- -------- ------------  ------- - - -
-
-- ZORAN ------------------------------------------------------
- Author: Pauline Middelink <middelin@polyware.nl>
-   Date: 18 September 1999
-Version: 0.6.1
-
-- Description ------------------------------------------------
-
-Video4Linux compatible driver for an unknown brand framegrabber
-(Sold in the Netherlands by TRUST Computer Products) and various
-other zoran zr36120 based framegrabbers.
-
-The card contains a ZR36120 Multimedia PCI Interface and a Philips
-SAA7110 Onechip Frontend videodecoder. There is also an DSP of
-which I have forgotten the number, since i will never get that thing
-to work without specs from the vendor itself.
-
-The SAA711x are capable of processing 6 different video inputs,
-CVBS1..6 and Y1+C1, Y2+C2, Y3+C3. All in 50/60Hz, NTSC, PAL or
-SECAM and delivering a YUV datastream.  On my card the input
-'CVBS-0' corresponds to channel CVBS2 and 'S-Video' to Y2+C2.
-
-I have some reports of other cards working with the mentioned
-chip sets. For a list of other working cards please have a look
-at the cards named in the tvcards struct in the beginning of
-zr36120.c
-
-After some testing, I discovered that the carddesigner messed up
-on the I2C interface. The Zoran chip includes 2 lines SDA and SCL
-which (s)he connected reversely. So we have to clock on the SDA
-and r/w data on the SCL pin. Life is fun... Each cardtype now has
-a bit which signifies if you have a card with the same deficiency.
-
-Oh, for the completeness of this story I must mention that my
-card delivers the VSYNC pulse of the SAA chip to GIRQ1, not
-GIRQ0 as some other cards have. This is also incorporated in
-the driver be clearing/setting the 'useirq1' bit in the tvcard
-description.
-
-Another problems of continuous capturing data with a Zoran chip
-is something nasty inside the chip. It effectively halves the
-fps we ought to get... Here is the scenario: capturing frames
-to memory is done in the so-called snapshot mode. In this mode
-the Zoran stops after capturing a frame worth of data and wait
-till the application set GRAB bit to indicate readiness for the
-next frame. After detecting a set bit, the chip neatly waits
-till the start of a frame, captures it and it goes back to off.
-Smart ppl will notice the problem here. Its the waiting on the
-_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps
-is still plenty fast for me.
--- update 28/7/1999 --
-Don't believe a word I just said... Proof is the output
-of `streamer -t 300 -r 25 -f avi15 -o /dev/null`
-       ++--+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25
-       +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+-
-       syncer: done
-       writer: done
-(note the /dev/null is prudent here, my system is not able to
- grab /and/ write 25 fps to a file... gifts welcome :) )
-The technical reasoning follows: The zoran completed the last
-frame, the VSYNC goes low, and GRAB is cleared. The interrupt
-routine starts to work since its VSYNC driven, and again
-activates the GRAB bit. A few ms later the VSYNC (re-)rises and
-the zoran starts to work on a new and freshly broadcasted frame....
-
-For pointers I used the specs of both chips. Below are the URLs:
-  http://www.zoran.com/ftp/download/devices/pci/ZR36120/36120data.pdf
-  http://www-us.semiconductor.philips.com/acrobat/datasheets/SAA_7110_A_1.pdf
-Some alternatives for the Philips SAA 7110 datasheet are:
-  http://www.datasheetcatalog.com/datasheets_pdf/S/A/A/7/SAA7110.shtml
-  http://www.datasheetarchive.com/search.php?search=SAA7110&sType=part
-
-The documentation has very little on absolute numbers or timings
-needed for the various modes/resolutions, but there are other
-programs you can borrow those from.
-
------- Install --------------------------------------------
-Read the file called TODO.  Note its long list of limitations.
-
-Build a kernel with VIDEO4LINUX enabled. Activate the
-BT848 driver; we need this because we have need for the
-other modules (i2c and videodev) it enables.
-
-To install this software, extract it into a suitable directory.
-Examine the makefile and change anything you don't like.  Type "make".
-
-After making the modules check if you have the much needed
-/dev/video devices. If not, execute the following 4 lines:
-       mknod /dev/video c 81 0
-       mknod /dev/video1 c 81 1
-       mknod /dev/video2 c 81 2
-       mknod /dev/video3 c 81 3
-       mknod /dev/video4 c 81 4
-
-After making/checking the devices do:
-       modprobe i2c
-       modprobe videodev
-       modprobe saa7110        (optional)
-       modprobe saa7111        (optional)
-       modprobe tuner          (optional)
-       insmod zoran cardtype=<n>
-
-<n> is the cardtype of the card you have. The cardnumber can
-be found in the source of zr36120. Look for tvcards. If your
-card is not there, please try if any other card gives some
-response, and mail me if you got a working tvcard addition.
-
-PS. <TVCard editors behold!)
-    Don't forget to set video_input to the number of inputs
-    you defined in the video_mux part of the tvcard definition.
-    It's a common error to add a channel but not incrementing
-    video_input and getting angry with me/v4l/linux/linus :(
-
-You are now ready to test the framegrabber with your favorite
-video4linux compatible tool
-
------- Application ----------------------------------------
-
-This device works with all Video4Linux compatible applications,
-given the limitations in the TODO file.
-
------- API ------------------------------------------------
-
-This uses the V4L interface as of kernel release 2.1.116, and in
-fact has not been tested on any lower version.  There are a couple
-of minor differences due to the fact that the amount of data returned
-with each frame varies, and no doubt there are discrepancies due to my
-misunderstanding of the API.  I intend to convert this driver to the
-new V4L2 API when it has stabilized more.
-
------- Current state --------------------------------------
-
-The driver is capable of overlaying a video image in screen, and
-even capable of grabbing frames. It uses the BIGPHYSAREA patch
-to allocate lots of large memory blocks when tis patch is
-found in the kernel, but it doesn't need it.
-The consequence is that, when loading the driver as a module,
-the module may tell you it's out of memory, but 'free' says
-otherwise. The reason is simple; the modules wants its memory
-contiguous, not fragmented, and after a long uptime there
-probably isn't a fragment of memory large enough...
-
-The driver uses a double buffering scheme, which should really
-be an n-way buffer, depending on the size of allocated framebuffer
-and the requested grab-size/format.
-This current version also fixes a dead-lock situation during irq
-time, which really, really froze my system... :)
-
-Good luck.
-  Pauline
index dbf449ba240c9f5b6cac91cfb6cfda27713599f2..b2024938adcf7cf8ad43d6e26fe7a6343acf5161 100644 (file)
@@ -2554,7 +2554,7 @@ S:        Maintained
 REAL TIME CLOCK (RTC) SUBSYSTEM
 P:     Alessandro Zummo
 M:     a.zummo@towertech.it
-L:     linux-kernel@vger.kernel.org
+L:     rtc-linux@googlegroups.com
 S:     Maintained
 
 REISERFS FILE SYSTEM
index aef96259051fa58211ec31b7f22b0bee3c595176..73e825b39a08d29da3ae24c630f0684f4c31f7c2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,11 @@ NAME=Avast! A bilge rat!
 # Comments in this file are targeted only to the developer, do not
 # expect to learn how to build the kernel reading this file.
 
-# Do not print "Entering directory ..."
-MAKEFLAGS += --no-print-directory
+# Do not:
+# o  use make's built-in rules and variables
+#    (this increases performance and avoid hard-to-debug behavour);
+# o  print "Entering directory ...";
+MAKEFLAGS += -rR --no-print-directory
 
 # We are using a recursive build, so we need to do a little thinking
 # to get the ordering right.
@@ -271,12 +274,8 @@ export quiet Q KBUILD_VERBOSE
 # Look for make include files relative to root of kernel src
 MAKEFLAGS += --include-dir=$(srctree)
 
-# We need some generic definitions
-include  $(srctree)/scripts/Kbuild.include
-
-# Do not use make's built-in rules and variables
-# This increases performance and avoid hard-to-debug behavour
-MAKEFLAGS += -rR
+# We need some generic definitions.
+include $(srctree)/scripts/Kbuild.include
 
 # Make variables (CC, etc...)
 
@@ -1484,6 +1483,8 @@ endif     # skip-makefile
 PHONY += FORCE
 FORCE:
 
+# Cancel implicit rules on top Makefile, `-rR' will apply to sub-makes.
+Makefile: ;
 
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable se we can use it in if_changed and friends.
index fb804043b32080b856dd3e176c9747258b747d62..be133f1f75a4d117d71544ba1536298051472d7d 100644 (file)
@@ -979,7 +979,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
        long timeout;
        int ret = -EINVAL;
        struct fdtable *fdt;
-       int max_fdset;
+       int max_fds;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -1003,9 +1003,9 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
 
        rcu_read_lock();
        fdt = files_fdtable(current->files);
-       max_fdset = fdt->max_fdset;
+       max_fds = fdt->max_fds;
        rcu_read_unlock();
-       if (n < 0 || n > max_fdset)
+       if (n < 0 || n > max_fds)
                goto out_nofds;
 
        /*
index cced73c58115f8323d4b19e95451ad76f4038374..32b361f31c2ce443a9c8760bd80ce6eeaade8d44 100644 (file)
@@ -7,20 +7,83 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/types.h>
 
+#include <asm/io.h>
+#include <asm/setup.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
 
-struct eth_platform_data __initdata eth0_data = {
-       .valid          = 1,
-       .mii_phy_addr   = 0x10,
-       .is_rmii        = 0,
-       .hw_addr        = { 0x6a, 0x87, 0x71, 0x14, 0xcd, 0xcb },
+struct eth_addr {
+       u8 addr[6];
 };
 
+static struct eth_addr __initdata hw_addr[2];
+
+static struct eth_platform_data __initdata eth_data[2];
 extern struct lcdc_platform_data atstk1000_fb0_data;
 
+/*
+ * The next two functions should go away as the boot loader is
+ * supposed to initialize the macb address registers with a valid
+ * ethernet address. But we need to keep it around for a while until
+ * we can be reasonably sure the boot loader does this.
+ *
+ * The phy_id is ignored as the driver will probe for it.
+ */
+static int __init parse_tag_ethernet(struct tag *tag)
+{
+       int i;
+
+       i = tag->u.ethernet.mac_index;
+       if (i < ARRAY_SIZE(hw_addr))
+               memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address,
+                      sizeof(hw_addr[i].addr));
+
+       return 0;
+}
+__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
+
+static void __init set_hw_addr(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       const u8 *addr;
+       void __iomem *regs;
+       struct clk *pclk;
+
+       if (!res)
+               return;
+       if (pdev->id >= ARRAY_SIZE(hw_addr))
+               return;
+
+       addr = hw_addr[pdev->id].addr;
+       if (!is_valid_ether_addr(addr))
+               return;
+
+       /*
+        * Since this is board-specific code, we'll cheat and use the
+        * physical address directly as we happen to know that it's
+        * the same as the virtual address.
+        */
+       regs = (void __iomem __force *)res->start;
+       pclk = clk_get(&pdev->dev, "pclk");
+       if (!pclk)
+               return;
+
+       clk_enable(pclk);
+       __raw_writel((addr[3] << 24) | (addr[2] << 16)
+                    | (addr[1] << 8) | addr[0], regs + 0x98);
+       __raw_writel((addr[5] << 8) | addr[4], regs + 0x9c);
+       clk_disable(pclk);
+       clk_put(pclk);
+}
+
 void __init setup_board(void)
 {
        at32_map_usart(1, 0);   /* /dev/ttyS0 */
@@ -38,7 +101,8 @@ static int __init atstk1002_init(void)
        at32_add_device_usart(1);
        at32_add_device_usart(2);
 
-       at32_add_device_eth(0, &eth0_data);
+       set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
+
        at32_add_device_spi(0);
        at32_add_device_lcdc(0, &atstk1000_fb0_data);
 
index 372e3f8b2417737c38d3be01bcd3990d4f71967e..7c4c76114bbafdaae522246bee5ba9e3c70fd1bc 100644 (file)
@@ -7,12 +7,12 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
 
 #include <asm/checksum.h>
 #include <asm/uaccess.h>
-#include <asm/delay.h>
 
 /*
  * GCC functions
index 317dc50945f231896ca079f382eebbfe67201cb4..0b4325946a41629cc7a4755a7c679311e85e688f 100644 (file)
@@ -38,6 +38,13 @@ void cpu_idle(void)
 
 void machine_halt(void)
 {
+       /*
+        * Enter Stop mode. The 32 kHz oscillator will keep running so
+        * the RTC will keep the time properly and the system will
+        * boot quickly.
+        */
+       asm volatile("sleep 3\n\t"
+                    "sub pc, -2");
 }
 
 void machine_power_off(void)
index ea2d1ffee4780c14ea6237f21090d1cbfd036f65..a34211601008420f456e185b825c9ed426eb51c7 100644 (file)
@@ -229,30 +229,6 @@ static int __init parse_tag_rsvd_mem(struct tag *tag)
 }
 __tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
 
-static int __init parse_tag_ethernet(struct tag *tag)
-{
-#if 0
-       const struct platform_device *pdev;
-
-       /*
-        * We really need a bus type that supports "classes"...this
-        * will do for now (until we must handle other kinds of
-        * ethernet controllers)
-        */
-       pdev = platform_get_device("macb", tag->u.ethernet.mac_index);
-       if (pdev && pdev->dev.platform_data) {
-               struct eth_platform_data *data = pdev->dev.platform_data;
-
-               data->valid = 1;
-               data->mii_phy_addr = tag->u.ethernet.mii_phy_addr;
-               memcpy(data->hw_addr, tag->u.ethernet.hw_address,
-                      sizeof(data->hw_addr));
-       }
-#endif
-       return 0;
-}
-__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
-
 /*
  * Scan the tag table for this tag, and call its parse function. The
  * tag table is built by the linker from all the __tagtable
index 462c8307b680fa00efd8a98e0010ac5ee991bbd3..b3bc0b56e2c6506849de3ba758aae262f552f477 100644 (file)
@@ -12,9 +12,9 @@
 
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/param.h>
 #include <linux/types.h>
 
-#include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 
index 7ff6ad8bab5faa5132871aa869edeec875dd2001..48f4ef38c70e4a097ead99b9dc8a3ccd8195048f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/io.h>
 
+#include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
 #include <asm/arch/sm.h>
@@ -57,6 +58,9 @@ static struct platform_device _name##_id##_device = {         \
        .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
 }
 
+#define select_peripheral(pin, periph, flags)                  \
+       at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+
 #define DEV_CLK(_name, devname, bus, _index)                   \
 static struct clk devname##_##_name = {                                \
        .name           = #_name,                               \
@@ -67,18 +71,6 @@ static struct clk devname##_##_name = {                              \
        .index          = _index,                               \
 }
 
-enum {
-       PIOA,
-       PIOB,
-       PIOC,
-       PIOD,
-};
-
-enum {
-       FUNC_A,
-       FUNC_B,
-};
-
 unsigned long at32ap7000_osc_rates[3] = {
        [0] = 32768,
        /* FIXME: these are ATSTK1002-specific */
@@ -569,26 +561,26 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
-       portmux_set_func(PIOA,  8, FUNC_B);     /* RXD  */
-       portmux_set_func(PIOA,  9, FUNC_B);     /* TXD  */
+       select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
+       select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
 }
 
 static inline void configure_usart1_pins(void)
 {
-       portmux_set_func(PIOA, 17, FUNC_A);     /* RXD  */
-       portmux_set_func(PIOA, 18, FUNC_A);     /* TXD  */
+       select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
+       select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
 }
 
 static inline void configure_usart2_pins(void)
 {
-       portmux_set_func(PIOB, 26, FUNC_B);     /* RXD  */
-       portmux_set_func(PIOB, 27, FUNC_B);     /* TXD  */
+       select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
+       select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
 }
 
 static inline void configure_usart3_pins(void)
 {
-       portmux_set_func(PIOB, 18, FUNC_B);     /* RXD  */
-       portmux_set_func(PIOB, 17, FUNC_B);     /* TXD  */
+       select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
+       select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
 }
 
 static struct platform_device *at32_usarts[4];
@@ -654,6 +646,15 @@ DEFINE_DEV_DATA(macb, 0);
 DEV_CLK(hclk, macb0, hsb, 8);
 DEV_CLK(pclk, macb0, pbb, 6);
 
+static struct eth_platform_data macb1_data;
+static struct resource macb1_resource[] = {
+       PBMEM(0xfff01c00),
+       IRQ(26),
+};
+DEFINE_DEV_DATA(macb, 1);
+DEV_CLK(hclk, macb1, hsb, 9);
+DEV_CLK(pclk, macb1, pbb, 7);
+
 struct platform_device *__init
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
 {
@@ -663,27 +664,54 @@ at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
        case 0:
                pdev = &macb0_device;
 
-               portmux_set_func(PIOC,  3, FUNC_A);     /* TXD0 */
-               portmux_set_func(PIOC,  4, FUNC_A);     /* TXD1 */
-               portmux_set_func(PIOC,  7, FUNC_A);     /* TXEN */
-               portmux_set_func(PIOC,  8, FUNC_A);     /* TXCK */
-               portmux_set_func(PIOC,  9, FUNC_A);     /* RXD0 */
-               portmux_set_func(PIOC, 10, FUNC_A);     /* RXD1 */
-               portmux_set_func(PIOC, 13, FUNC_A);     /* RXER */
-               portmux_set_func(PIOC, 15, FUNC_A);     /* RXDV */
-               portmux_set_func(PIOC, 16, FUNC_A);     /* MDC  */
-               portmux_set_func(PIOC, 17, FUNC_A);     /* MDIO */
+               select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
+               select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
+               select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
+               select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
+               select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
+               select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
+               select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
+               select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
+               select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
+               select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+
+               if (!data->is_rmii) {
+                       select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
+                       select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
+                       select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
+                       select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
+                       select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
+                       select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
+                       select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
+                       select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
+                       select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
+               }
+               break;
+
+       case 1:
+               pdev = &macb1_device;
+
+               select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
+               select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
+               select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
+               select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
+               select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
+               select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
+               select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
+               select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
+               select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
+               select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
 
                if (!data->is_rmii) {
-                       portmux_set_func(PIOC,  0, FUNC_A);     /* COL  */
-                       portmux_set_func(PIOC,  1, FUNC_A);     /* CRS  */
-                       portmux_set_func(PIOC,  2, FUNC_A);     /* TXER */
-                       portmux_set_func(PIOC,  5, FUNC_A);     /* TXD2 */
-                       portmux_set_func(PIOC,  6, FUNC_A);     /* TXD3 */
-                       portmux_set_func(PIOC, 11, FUNC_A);     /* RXD2 */
-                       portmux_set_func(PIOC, 12, FUNC_A);     /* RXD3 */
-                       portmux_set_func(PIOC, 14, FUNC_A);     /* RXCK */
-                       portmux_set_func(PIOC, 18, FUNC_A);     /* SPD  */
+                       select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
+                       select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
+                       select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
+                       select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
+                       select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
+                       select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
+                       select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
+                       select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
+                       select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
                }
                break;
 
@@ -714,12 +742,12 @@ struct platform_device *__init at32_add_device_spi(unsigned int id)
        switch (id) {
        case 0:
                pdev = &spi0_device;
-               portmux_set_func(PIOA,  0, FUNC_A);     /* MISO  */
-               portmux_set_func(PIOA,  1, FUNC_A);     /* MOSI  */
-               portmux_set_func(PIOA,  2, FUNC_A);     /* SCK   */
-               portmux_set_func(PIOA,  3, FUNC_A);     /* NPCS0 */
-               portmux_set_func(PIOA,  4, FUNC_A);     /* NPCS1 */
-               portmux_set_func(PIOA,  5, FUNC_A);     /* NPCS2 */
+               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
+               select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
+               select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
+               select_peripheral(PA(3),  PERIPH_A, 0); /* NPCS0 */
+               select_peripheral(PA(4),  PERIPH_A, 0); /* NPCS1 */
+               select_peripheral(PA(5),  PERIPH_A, 0); /* NPCS2 */
                break;
 
        default:
@@ -762,37 +790,37 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
        switch (id) {
        case 0:
                pdev = &lcdc0_device;
-               portmux_set_func(PIOC, 19, FUNC_A);     /* CC     */
-               portmux_set_func(PIOC, 20, FUNC_A);     /* HSYNC  */
-               portmux_set_func(PIOC, 21, FUNC_A);     /* PCLK   */
-               portmux_set_func(PIOC, 22, FUNC_A);     /* VSYNC  */
-               portmux_set_func(PIOC, 23, FUNC_A);     /* DVAL   */
-               portmux_set_func(PIOC, 24, FUNC_A);     /* MODE   */
-               portmux_set_func(PIOC, 25, FUNC_A);     /* PWR    */
-               portmux_set_func(PIOC, 26, FUNC_A);     /* DATA0  */
-               portmux_set_func(PIOC, 27, FUNC_A);     /* DATA1  */
-               portmux_set_func(PIOC, 28, FUNC_A);     /* DATA2  */
-               portmux_set_func(PIOC, 29, FUNC_A);     /* DATA3  */
-               portmux_set_func(PIOC, 30, FUNC_A);     /* DATA4  */
-               portmux_set_func(PIOC, 31, FUNC_A);     /* DATA5  */
-               portmux_set_func(PIOD,  0, FUNC_A);     /* DATA6  */
-               portmux_set_func(PIOD,  1, FUNC_A);     /* DATA7  */
-               portmux_set_func(PIOD,  2, FUNC_A);     /* DATA8  */
-               portmux_set_func(PIOD,  3, FUNC_A);     /* DATA9  */
-               portmux_set_func(PIOD,  4, FUNC_A);     /* DATA10 */
-               portmux_set_func(PIOD,  5, FUNC_A);     /* DATA11 */
-               portmux_set_func(PIOD,  6, FUNC_A);     /* DATA12 */
-               portmux_set_func(PIOD,  7, FUNC_A);     /* DATA13 */
-               portmux_set_func(PIOD,  8, FUNC_A);     /* DATA14 */
-               portmux_set_func(PIOD,  9, FUNC_A);     /* DATA15 */
-               portmux_set_func(PIOD, 10, FUNC_A);     /* DATA16 */
-               portmux_set_func(PIOD, 11, FUNC_A);     /* DATA17 */
-               portmux_set_func(PIOD, 12, FUNC_A);     /* DATA18 */
-               portmux_set_func(PIOD, 13, FUNC_A);     /* DATA19 */
-               portmux_set_func(PIOD, 14, FUNC_A);     /* DATA20 */
-               portmux_set_func(PIOD, 15, FUNC_A);     /* DATA21 */
-               portmux_set_func(PIOD, 16, FUNC_A);     /* DATA22 */
-               portmux_set_func(PIOD, 17, FUNC_A);     /* DATA23 */
+               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
+               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
+               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
+               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
+               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
+               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
+               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
+               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
+               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
+               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
+               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
+               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
+               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
+               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
 
                clk_set_parent(&lcdc0_pixclk, &pll0);
                clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
@@ -838,6 +866,8 @@ struct clk *at32_clock_list[] = {
        &atmel_usart3_usart,
        &macb0_hclk,
        &macb0_pclk,
+       &macb1_hclk,
+       &macb1_pclk,
        &spi0_mck,
        &lcdc0_hclk,
        &lcdc0_pixclk,
index 4dff1f98890039f0d96fcbc54e27c76322e3e383..b59272e81b9a049be31be3105d23354742d11388 100644 (file)
@@ -49,12 +49,25 @@ static void eim_unmask_irq(unsigned int irq)
 static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
 {
        struct at32_sm *sm = get_irq_chip_data(irq);
+       struct irq_desc *desc;
        unsigned int i = irq - sm->eim_first_irq;
        u32 mode, edge, level;
        unsigned long flags;
        int ret = 0;
 
-       flow_type &= IRQ_TYPE_SENSE_MASK;
+       if (flow_type == IRQ_TYPE_NONE)
+               flow_type = IRQ_TYPE_LEVEL_LOW;
+
+       desc = &irq_desc[irq];
+       desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+       desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+
+       if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
+               desc->status |= IRQ_LEVEL;
+               set_irq_handler(irq, handle_level_irq);
+       } else {
+               set_irq_handler(irq, handle_edge_irq);
+       }
 
        spin_lock_irqsave(&sm->lock, flags);
 
@@ -148,10 +161,15 @@ static int __init eim_init(void)
        pattern = sm_readl(sm, EIM_MODE);
        nr_irqs = fls(pattern);
 
+       /* Trigger on falling edge unless overridden by driver */
+       sm_writel(sm, EIM_MODE, 0UL);
+       sm_writel(sm, EIM_EDGE, 0UL);
+
        sm->eim_chip = &eim_chip;
 
        for (i = 0; i < nr_irqs; i++) {
-               set_irq_chip(sm->eim_first_irq + i, &eim_chip);
+               set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+                                        handle_edge_irq);
                set_irq_chip_data(sm->eim_first_irq + i, sm);
        }
 
index eb87a18ad7b2f70c6a49a7595efeca4ac23706b1..dd5c009cf224838379af65d498c35ed7357afcf2 100644 (file)
@@ -136,3 +136,7 @@ fail:
        panic("Interrupt controller initialization failed!\n");
 }
 
+unsigned long intc_get_pending(int group)
+{
+       return intc_readl(&intc0, INTREQ0 + 4 * group);
+}
index d3aabfca85987c35248e87d632827394bae9e70f..f1280ed8ed6dcb6a7b48fd5418d3c116e3bb7794 100644 (file)
@@ -25,27 +25,98 @@ struct pio_device {
        void __iomem *regs;
        const struct platform_device *pdev;
        struct clk *clk;
-       u32 alloc_mask;
+       u32 pinmux_mask;
        char name[32];
 };
 
 static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
 
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
-                     unsigned int function_id)
+static struct pio_device *gpio_to_pio(unsigned int gpio)
 {
        struct pio_device *pio;
-       u32 mask = 1 << pin_id;
+       unsigned int index;
 
-       BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
+       index = gpio >> 5;
+       if (index >= MAX_NR_PIO_DEVICES)
+               return NULL;
+       pio = &pio_dev[index];
+       if (!pio->regs)
+               return NULL;
 
-       pio = &pio_dev[portmux_id];
+       return pio;
+}
+
+/* Pin multiplexing API */
+
+void __init at32_select_periph(unsigned int pin, unsigned int periph,
+                              unsigned long flags)
+{
+       struct pio_device *pio;
+       unsigned int pin_index = pin & 0x1f;
+       u32 mask = 1 << pin_index;
+
+       pio = gpio_to_pio(pin);
+       if (unlikely(!pio)) {
+               printk("pio: invalid pin %u\n", pin);
+               goto fail;
+       }
 
-       if (function_id)
+       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+               printk("%s: pin %u is busy\n", pio->name, pin_index);
+               goto fail;
+       }
+
+       pio_writel(pio, PUER, mask);
+       if (periph)
                pio_writel(pio, BSR, mask);
        else
                pio_writel(pio, ASR, mask);
+
        pio_writel(pio, PDR, mask);
+       if (!(flags & AT32_GPIOF_PULLUP))
+               pio_writel(pio, PUDR, mask);
+
+       return;
+
+fail:
+       dump_stack();
+}
+
+void __init at32_select_gpio(unsigned int pin, unsigned long flags)
+{
+       struct pio_device *pio;
+       unsigned int pin_index = pin & 0x1f;
+       u32 mask = 1 << pin_index;
+
+       pio = gpio_to_pio(pin);
+       if (unlikely(!pio)) {
+               printk("pio: invalid pin %u\n", pin);
+               goto fail;
+       }
+
+       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+               printk("%s: pin %u is busy\n", pio->name, pin_index);
+               goto fail;
+       }
+
+       pio_writel(pio, PUER, mask);
+       if (flags & AT32_GPIOF_HIGH)
+               pio_writel(pio, SODR, mask);
+       else
+               pio_writel(pio, CODR, mask);
+       if (flags & AT32_GPIOF_OUTPUT)
+               pio_writel(pio, OER, mask);
+       else
+               pio_writel(pio, ODR, mask);
+
+       pio_writel(pio, PER, mask);
+       if (!(flags & AT32_GPIOF_PULLUP))
+               pio_writel(pio, PUDR, mask);
+
+       return;
+
+fail:
+       dump_stack();
 }
 
 static int __init pio_probe(struct platform_device *pdev)
diff --git a/arch/avr32/mach-at32ap/sm.c b/arch/avr32/mach-at32ap/sm.c
deleted file mode 100644 (file)
index 03306eb..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * System Manager driver for AT32AP CPUs
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * 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/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/spinlock.h>
-
-#include <asm/intc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <asm/arch/sm.h>
-
-#include "sm.h"
-
-#define SM_EIM_IRQ_RESOURCE    1
-#define SM_PM_IRQ_RESOURCE     2
-#define SM_RTC_IRQ_RESOURCE    3
-
-#define to_eim(irqc) container_of(irqc, struct at32_sm, irqc)
-
-struct at32_sm system_manager;
-
-int __init at32_sm_init(void)
-{
-       struct resource *regs;
-       struct at32_sm *sm = &system_manager;
-       int ret = -ENXIO;
-
-       regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
-       if (!regs)
-               goto fail;
-
-       spin_lock_init(&sm->lock);
-       sm->pdev = &at32_sm_device;
-
-       ret = -ENOMEM;
-       sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
-       if (!sm->regs)
-               goto fail;
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
-       return ret;
-}
-
-/*
- * External Interrupt Module (EIM).
- *
- * EIM gets level- or edge-triggered interrupts of either polarity
- * from the outside and converts it to active-high level-triggered
- * interrupts that the internal interrupt controller can handle. EIM
- * also provides masking/unmasking of interrupts, as well as
- * acknowledging of edge-triggered interrupts.
- */
-
-static irqreturn_t spurious_eim_interrupt(int irq, void *dev_id,
-                                         struct pt_regs *regs)
-{
-       printk(KERN_WARNING "Spurious EIM interrupt %d\n", irq);
-       disable_irq(irq);
-       return IRQ_NONE;
-}
-
-static struct irqaction eim_spurious_action = {
-       .handler = spurious_eim_interrupt,
-};
-
-static irqreturn_t eim_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-       struct irq_controller * irqc = dev_id;
-       struct at32_sm *sm = to_eim(irqc);
-       unsigned long pending;
-
-       /*
-        * No need to disable interrupts globally.  The interrupt
-        * level relevant to this group must be masked all the time,
-        * so we know that this particular EIM instance will not be
-        * re-entered.
-        */
-       spin_lock(&sm->lock);
-
-       pending = intc_get_pending(sm->irqc.irq_group);
-       if (unlikely(!pending)) {
-               printk(KERN_ERR "EIM (group %u): No interrupts pending!\n",
-                      sm->irqc.irq_group);
-               goto unlock;
-       }
-
-       do {
-               struct irqaction *action;
-               unsigned int i;
-
-               i = fls(pending) - 1;
-               pending &= ~(1 << i);
-               action = sm->action[i];
-
-               /* Acknowledge the interrupt */
-               sm_writel(sm, EIM_ICR, 1 << i);
-
-               spin_unlock(&sm->lock);
-
-               if (action->flags & SA_INTERRUPT)
-                       local_irq_disable();
-               action->handler(sm->irqc.first_irq + i, action->dev_id, regs);
-               local_irq_enable();
-               spin_lock(&sm->lock);
-               if (action->flags & SA_SAMPLE_RANDOM)
-                       add_interrupt_randomness(sm->irqc.first_irq + i);
-       } while (pending);
-
-unlock:
-       spin_unlock(&sm->lock);
-       return IRQ_HANDLED;
-}
-
-static void eim_mask(struct irq_controller *irqc, unsigned int irq)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       unsigned int i;
-
-       i = irq - sm->irqc.first_irq;
-       sm_writel(sm, EIM_IDR, 1 << i);
-}
-
-static void eim_unmask(struct irq_controller *irqc, unsigned int irq)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       unsigned int i;
-
-       i = irq - sm->irqc.first_irq;
-       sm_writel(sm, EIM_IER, 1 << i);
-}
-
-static int eim_setup(struct irq_controller *irqc, unsigned int irq,
-               struct irqaction *action)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       sm->action[irq - sm->irqc.first_irq] = action;
-       /* Acknowledge earlier interrupts */
-       sm_writel(sm, EIM_ICR, (1<<(irq - sm->irqc.first_irq)));
-       eim_unmask(irqc, irq);
-       return 0;
-}
-
-static void eim_free(struct irq_controller *irqc, unsigned int irq,
-               void *dev)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       eim_mask(irqc, irq);
-       sm->action[irq - sm->irqc.first_irq] = &eim_spurious_action;
-}
-
-static int eim_set_type(struct irq_controller *irqc, unsigned int irq,
-                       unsigned int type)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       unsigned long flags;
-       u32 value, pattern;
-
-       spin_lock_irqsave(&sm->lock, flags);
-
-       pattern = 1 << (irq - sm->irqc.first_irq);
-
-       value = sm_readl(sm, EIM_MODE);
-       if (type & IRQ_TYPE_LEVEL)
-               value |= pattern;
-       else
-               value &= ~pattern;
-       sm_writel(sm, EIM_MODE, value);
-       value = sm_readl(sm, EIM_EDGE);
-       if (type & IRQ_EDGE_RISING)
-               value |= pattern;
-       else
-               value &= ~pattern;
-       sm_writel(sm, EIM_EDGE, value);
-       value = sm_readl(sm, EIM_LEVEL);
-       if (type & IRQ_LEVEL_HIGH)
-               value |= pattern;
-       else
-               value &= ~pattern;
-       sm_writel(sm, EIM_LEVEL, value);
-
-       spin_unlock_irqrestore(&sm->lock, flags);
-
-       return 0;
-}
-
-static unsigned int eim_get_type(struct irq_controller *irqc,
-                                unsigned int irq)
-{
-       struct at32_sm *sm = to_eim(irqc);
-       unsigned long flags;
-       unsigned int type = 0;
-       u32 mode, edge, level, pattern;
-
-       pattern = 1 << (irq - sm->irqc.first_irq);
-
-       spin_lock_irqsave(&sm->lock, flags);
-       mode = sm_readl(sm, EIM_MODE);
-       edge = sm_readl(sm, EIM_EDGE);
-       level = sm_readl(sm, EIM_LEVEL);
-       spin_unlock_irqrestore(&sm->lock, flags);
-
-       if (mode & pattern)
-               type |= IRQ_TYPE_LEVEL;
-       if (edge & pattern)
-               type |= IRQ_EDGE_RISING;
-       if (level & pattern)
-               type |= IRQ_LEVEL_HIGH;
-
-       return type;
-}
-
-static struct irq_controller_class eim_irq_class = {
-       .typename       = "EIM",
-       .handle         = eim_handle_irq,
-       .setup          = eim_setup,
-       .free           = eim_free,
-       .mask           = eim_mask,
-       .unmask         = eim_unmask,
-       .set_type       = eim_set_type,
-       .get_type       = eim_get_type,
-};
-
-static int __init eim_init(void)
-{
-       struct at32_sm *sm = &system_manager;
-       unsigned int i;
-       u32 pattern;
-       int ret;
-
-       /*
-        * The EIM is really the same module as SM, so register
-        * mapping, etc. has been taken care of already.
-        */
-
-       /*
-        * Find out how many interrupt lines that are actually
-        * implemented in hardware.
-        */
-       sm_writel(sm, EIM_IDR, ~0UL);
-       sm_writel(sm, EIM_MODE, ~0UL);
-       pattern = sm_readl(sm, EIM_MODE);
-       sm->irqc.nr_irqs = fls(pattern);
-
-       ret = -ENOMEM;
-       sm->action = kmalloc(sizeof(*sm->action) * sm->irqc.nr_irqs,
-                            GFP_KERNEL);
-       if (!sm->action)
-               goto out;
-
-       for (i = 0; i < sm->irqc.nr_irqs; i++)
-               sm->action[i] = &eim_spurious_action;
-
-       spin_lock_init(&sm->lock);
-       sm->irqc.irq_group = sm->pdev->resource[SM_EIM_IRQ_RESOURCE].start;
-       sm->irqc.class = &eim_irq_class;
-
-       ret = intc_register_controller(&sm->irqc);
-       if (ret < 0)
-               goto out_free_actions;
-
-       printk("EIM: External Interrupt Module at 0x%p, IRQ group %u\n",
-              sm->regs, sm->irqc.irq_group);
-       printk("EIM: Handling %u external IRQs, starting with IRQ%u\n",
-              sm->irqc.nr_irqs, sm->irqc.first_irq);
-
-       return 0;
-
-out_free_actions:
-       kfree(sm->action);
-out:
-       return ret;
-}
-arch_initcall(eim_init);
index c1d9fc8f1a859f8d365abbcfc6efc2949bf2e092..ee677ced7b68413b098e6e192815afb067c1cdf8 100644 (file)
@@ -223,7 +223,7 @@ static int cmode_procctl(ctl_table *ctl, int write, struct file *filp,
 
 static int cmode_sysctl(ctl_table *table, int __user *name, int nlen,
                        void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen, void **context)
+                       void __user *newval, size_t newlen)
 {
        if (oldval && oldlenp) {
                size_t oldlen;
@@ -326,7 +326,7 @@ static int p0_procctl(ctl_table *ctl, int write, struct file *filp,
 
 static int p0_sysctl(ctl_table *table, int __user *name, int nlen,
                     void __user *oldval, size_t __user *oldlenp,
-                    void __user *newval, size_t newlen, void **context)
+                    void __user *newval, size_t newlen)
 {
        if (oldval && oldlenp) {
                size_t oldlen;
@@ -370,7 +370,7 @@ static int cm_procctl(ctl_table *ctl, int write, struct file *filp,
 
 static int cm_sysctl(ctl_table *table, int __user *name, int nlen,
                     void __user *oldval, size_t __user *oldlenp,
-                    void __user *newval, size_t newlen, void **context)
+                    void __user *newval, size_t newlen)
 {
        if (oldval && oldlenp) {
                size_t oldlen;
index 1f9300f37f52f36528da5f07b3c6a1c797e89a63..96e941084c04f1fa2beae8d912e8381b062a0c5a 100644 (file)
@@ -644,7 +644,85 @@ CONFIG_CONNECTOR=m
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+# 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
 
 #
 # Parallel port support
index 2c82412b9efe9ba885419cd80609e754b5d99400..5929f883e46b66f44966edf418132750e316296e 100644 (file)
@@ -301,7 +301,7 @@ static void sp_cleanup(void)
        for (;;) {
                unsigned long set;
                i = j * __NFDBITS;
-               if (i >= fdt->max_fdset || i >= fdt->max_fds)
+               if (i >= fdt->max_fds)
                        break;
                set = fdt->open_fds->fds_bits[j++];
                while (set) {
index 621037db22904ed85f15ee0204007e6bade30e0d..060563a712b6064d837d85a529723bc770caeeee 100644 (file)
@@ -23,6 +23,8 @@ void (*_machine_restart)(char *command);
 void (*_machine_halt)(void);
 void (*pm_power_off)(void);
 
+EXPORT_SYMBOL(pm_power_off);
+
 void machine_restart(char *command)
 {
        if (_machine_restart)
index 79f0317d84ac6fa2fa99fcc02a916acac335f396..cecff24cc9721a16e7abdb9e04980f73b53293ec 100644 (file)
@@ -112,6 +112,7 @@ SECTIONS
     /* .exit.text is discarded at runtime, not link time, to deal with
      references from .rodata */
   .exit.text : { *(.exit.text) }
+  .exit.data : { *(.exit.data) }
   . = ALIGN(_PAGE_SIZE);
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
@@ -139,7 +140,6 @@ SECTIONS
 
   /* Sections to be discarded */
   /DISCARD/ : {
-        *(.exit.data)
         *(.exitcall.exit)
 
        /* ABI crap starts here */
index da35d45554911d64cbd68d37e0ec36c5917231e3..12878359f2c883673950f0e90ec2da01732c543d 100644 (file)
@@ -40,12 +40,12 @@ static DEFINE_MUTEX(lasat_info_mutex);
 /* Strategy function to write EEPROM after changing string entry */
 int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
                void *oldval, size_t *oldlenp,
-               void *newval, size_t newlen, void **context)
+               void *newval, size_t newlen)
 {
        int r;
        mutex_lock(&lasat_info_mutex);
        r = sysctl_string(table, name,
-                         nlen, oldval, oldlenp, newval, newlen, context);
+                         nlen, oldval, oldlenp, newval, newlen);
        if (r < 0) {
                mutex_unlock(&lasat_info_mutex);
                return r;
@@ -119,11 +119,11 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
 /* Sysctl for setting the IP addresses */
 int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
                    void *oldval, size_t *oldlenp,
-                   void *newval, size_t newlen, void **context)
+                   void *newval, size_t newlen)
 {
        int r;
        mutex_lock(&lasat_info_mutex);
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
        if (r < 0) {
                mutex_unlock(&lasat_info_mutex);
                return r;
@@ -139,14 +139,14 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
 /* Same for RTC */
 int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
                    void *oldval, size_t *oldlenp,
-                   void *newval, size_t newlen, void **context)
+                   void *newval, size_t newlen)
 {
        int r;
        mutex_lock(&lasat_info_mutex);
        rtctmp = ds1603_read();
        if (rtctmp < 0)
                rtctmp = 0;
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
        if (r < 0) {
                mutex_unlock(&lasat_info_mutex);
                return r;
@@ -251,13 +251,12 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
 
 static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
                                     void *oldval, size_t *oldlenp,
-                                    void *newval, size_t newlen,
-                                    void **context)
+                                    void *newval, size_t newlen)
 {
        int r;
 
        mutex_lock(&lasat_info_mutex);
-       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+       r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
        if (r < 0) {
                mutex_unlock(&lasat_info_mutex);
                return r;
index 1720f2ceeeae981551756c92e1bc9dc65e76d70e..06771040a267ada35c44fa9fde31e8dce0342285 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (C) 1998, 1999 Ralf Baechle
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
 #include <asm/string.h>
@@ -29,6 +30,8 @@ __wsum csum_partial_copy_nocheck(const void *src,
        return sum;
 }
 
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
 /*
  * Copy from userspace and compute checksum.  If we catch an exception
  * then zero the rest of the buffer.
index 77ee5c6d33c119964da2619f5484cf83772e3b49..b662c75fb28e1080a6667f29c2a5775f774ec23e 100644 (file)
@@ -19,5 +19,5 @@
 # under Linux.
 #
 
-obj-y := malta_int.o malta_setup.o
+obj-y := malta_int.o malta_mtd.o malta_setup.o
 obj-$(CONFIG_SMP) += malta_smp.o
index 282f3e52eea3622eb1d00fd9ca710ac8e41cbda4..56ea76679cd41d816313f0a1eec1b13c19a5900e 100644 (file)
 #include <linux/pci.h>
 #include <linux/screen_info.h>
 
-#ifdef CONFIG_MTD
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#endif
-
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
@@ -58,30 +51,6 @@ struct resource standard_io_resources[] = {
        { .name = "dma2", .start = 0xc0, .end = 0xdf, .flags = IORESOURCE_BUSY },
 };
 
-#ifdef CONFIG_MTD
-static struct mtd_partition malta_mtd_partitions[] = {
-       {
-               .name =         "YAMON",
-               .offset =       0x0,
-               .size =         0x100000,
-               .mask_flags =   MTD_WRITEABLE
-       },
-       {
-               .name =         "User FS",
-               .offset =       0x100000,
-               .size =         0x2e0000
-       },
-       {
-               .name =         "Board Config",
-               .offset =       0x3e0000,
-               .size =         0x020000,
-               .mask_flags =   MTD_WRITEABLE
-       }
-};
-
-#define number_partitions      (sizeof(malta_mtd_partitions)/sizeof(struct mtd_partition))
-#endif
-
 const char *get_system_type(void)
 {
        return "MIPS Malta";
@@ -211,14 +180,6 @@ void __init plat_mem_setup(void)
 #endif
 #endif
 
-#ifdef CONFIG_MTD
-       /*
-        * Support for MTD on Malta. Use the generic physmap driver
-        */
-       physmap_configure(0x1e000000, 0x400000, 4, NULL);
-       physmap_set_partitions(malta_mtd_partitions, number_partitions);
-#endif
-
        mips_reboot_setup();
 
        board_time_init = mips_time_init;
index caf807ded51415aea2f6d9ba63a7458970f4f3dc..1f954a238a6332b0d8aaa0a4dde2fc5903f4f225 100644 (file)
@@ -32,6 +32,7 @@ void (*local_flush_data_cache_page)(void * addr);
 void (*flush_data_cache_page)(unsigned long addr);
 void (*flush_icache_all)(void);
 
+EXPORT_SYMBOL_GPL(local_flush_data_cache_page);
 EXPORT_SYMBOL(flush_data_cache_page);
 
 #ifdef CONFIG_DMA_NONCOHERENT
index 9e29ba9205f0c187925edd51214849f4567d89f5..ea2d15370bb72ecef36f99656049b092073bff9c 100644 (file)
@@ -316,7 +316,7 @@ static int __init page_is_ram(unsigned long pagenr)
 void __init paging_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES] = { 0, };
-       unsigned long max_dma, high, low;
+       unsigned long max_dma, low;
 #ifndef CONFIG_FLATMEM
        unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
        unsigned long i, j, pfn;
@@ -331,7 +331,6 @@ void __init paging_init(void)
 
        max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
        low = max_low_pfn;
-       high = highend_pfn;
 
 #ifdef CONFIG_ISA
        if (low < max_dma)
@@ -344,13 +343,13 @@ void __init paging_init(void)
        zones_size[ZONE_DMA] = low;
 #endif
 #ifdef CONFIG_HIGHMEM
-       if (cpu_has_dc_aliases) {
-               printk(KERN_WARNING "This processor doesn't support highmem.");
-               if (high - low)
-                       printk(" %ldk highmem ignored", high - low);
-               printk("\n");
-       } else
-               zones_size[ZONE_HIGHMEM] = high - low;
+       zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
+
+       if (cpu_has_dc_aliases && zones_size[ZONE_HIGHMEM]) {
+               printk(KERN_WARNING "This processor doesn't support highmem."
+                      " %ldk highmem ignored\n", zones_size[ZONE_HIGHMEM]);
+               zones_size[ZONE_HIGHMEM] = 0;
+       }
 #endif
 
 #ifdef CONFIG_FLATMEM
index 56c3c4065eb0c354fab33618ded153b43a1648b7..8699dadcd0966028ed7207b333486b2295a4fc12 100644 (file)
@@ -107,6 +107,11 @@ config AUDIT_ARCH
        bool
        default y
 
+config GENERIC_BUG
+       bool
+       default y
+       depends on BUG
+
 config DEFAULT_UIMAGE
        bool
        help
@@ -478,6 +483,7 @@ config PPC_MAPLE
        select PPC_UDBG_16550
        select PPC_970_NAP
        select PPC_NATIVE
+       select PPC_RTAS
        default n
        help
           This option enables support for the Maple 970FX Evaluation Board.
@@ -714,7 +720,7 @@ config FORCE_MAX_ZONEORDER
 
 config MATH_EMULATION
        bool "Math emulation"
-       depends on 4xx || 8xx || E200 || E500
+       depends on 4xx || 8xx || E200 || PPC_83xx || E500
        ---help---
          Some PowerPC chips designed for embedded applications do not have
          a floating-point unit and therefore do not implement the
index f2d888e014a9f81cbf296ec2ca8af3bf8ef570d9..70ed61337f5c03ad20b3775055c2baf4a99b0466 100644 (file)
@@ -157,6 +157,7 @@ CONFIG_SPU_BASE=y
 CONFIG_PS3_HTAB_SIZE=20
 CONFIG_PS3_DYNAMIC_DMA=y
 CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
 
 #
 # Kernel options
index 4fe53d08ab817e79a4810b1492e3a5e4bff02661..d2ded19e40643f4b7bafdaa28ba89ad0b443462d 100644 (file)
@@ -77,6 +77,7 @@ endif
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 extra-y += lparmap.s
+$(obj)/head_64.o:      $(obj)/lparmap.s
 AFLAGS_head_64.o += -I$(obj)
 endif
 
index 9d1614c3ce67d047adf9573dcb40704602783a5a..b742013bb9da2f6fbc70b86d2fea909e707e6881 100644 (file)
@@ -833,7 +833,7 @@ static struct cpu_spec cpu_specs[] = {
                .pvr_mask               = 0x7fff0000,
                .pvr_value              = 0x00840000,
                .cpu_name               = "e300c2",
-               .cpu_features           = CPU_FTRS_E300,
+               .cpu_features           = CPU_FTRS_E300C2,
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
@@ -1136,8 +1136,7 @@ static struct cpu_spec cpu_specs[] = {
                .pvr_mask               = 0xff000fff,
                .pvr_value              = 0x53000890,
                .cpu_name               = "440SPe Rev. A",
-               .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
-                       CPU_FTR_USE_TB,
+               .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
index d88e182e40b3849ba085ec3f83265adac690e538..9417cf5b4b7e7af4b361b0075a3b3c4d96dd2416 100644 (file)
@@ -437,6 +437,13 @@ Alignment:
 /* Floating-point unavailable */
        . = 0x800
 FPUnavailable:
+BEGIN_FTR_SECTION
+/*
+ * Certain Freescale cores don't have a FPU and treat fp instructions
+ * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
+ */
+       b       ProgramCheck
+END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
        EXCEPTION_PROLOG
        bne     load_up_fpu             /* if from user, just load it up */
        addi    r3,r1,STACK_FRAME_OVERHEAD
index e2c3c6a85f33b4180cd8f9d812e831e2f4c4176c..8339fd609de045c6c92777594009f9492391163d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/cache.h>
+#include <linux/bug.h>
 
 #include "setup.h"
 
@@ -290,23 +291,11 @@ int module_finalize(const Elf_Ehdr *hdr,
                    struct module *me)
 {
        const Elf_Shdr *sect;
+       int err;
 
-       me->arch.bug_table = NULL;
-       me->arch.num_bugs = 0;
-
-       /* Find the __bug_table section, if present */
-       sect = find_section(hdr, sechdrs, "__bug_table");
-       if (sect != NULL) {
-               me->arch.bug_table = (void *) sect->sh_addr;
-               me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-       }
-
-       /*
-        * Strictly speaking this should have a spinlock to protect against
-        * traversals, but since we only traverse on BUG()s, a spinlock
-        * could potentially lead to deadlock and thus be counter-productive.
-        */
-       list_add(&me->arch.bug_list, &module_bug_list);
+       err = module_bug_finalize(hdr, sechdrs, me);
+       if (err)                /* never true, currently */
+               return err;
 
        /* Apply feature fixups */
        sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -320,7 +309,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-       list_del(&mod->arch.bug_list);
+       module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
index 8dd1f0aae5d6265809748dcc0e0001b2a55e440e..75c7c4f1928059689353927c2c67d198c62e715f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/moduleloader.h>
 #include <linux/err.h>
 #include <linux/vmalloc.h>
+#include <linux/bug.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
@@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr,
                const Elf_Shdr *sechdrs, struct module *me)
 {
        const Elf_Shdr *sect;
+       int err;
 
-       me->arch.bug_table = NULL;
-       me->arch.num_bugs = 0;
-
-       /* Find the __bug_table section, if present */
-       sect = find_section(hdr, sechdrs, "__bug_table");
-       if (sect != NULL) {
-               me->arch.bug_table = (void *) sect->sh_addr;
-               me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-       }
-
-       /*
-        * Strictly speaking this should have a spinlock to protect against
-        * traversals, but since we only traverse on BUG()s, a spinlock
-        * could potentially lead to deadlock and thus be counter-productive.
-        */
-       list_add(&me->arch.bug_list, &module_bug_list);
+       err = module_bug_finalize(hdr, sechdrs, me);
+       if (err)
+               return err;
 
        /* Apply feature fixups */
        sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-       list_del(&mod->arch.bug_list);
+       module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
index 8a06724e029e4fd1f8cee862b95bd7101839ed20..e921514e655bd45a2b96438151e2a2f07d66b10e 100644 (file)
@@ -109,9 +109,7 @@ int of_device_register(struct of_device *ofdev)
        if (rc)
                return rc;
 
-       device_create_file(&ofdev->dev, &dev_attr_devspec);
-
-       return 0;
+       return device_create_file(&ofdev->dev, &dev_attr_devspec);
 }
 
 void of_device_unregister(struct of_device *ofdev)
index b3189d0161b8d7b4f9a60ac0db8c1804a55584a9..3002ea3a61a24df59fd437ecbd80866af1e3c6d6 100644 (file)
@@ -169,7 +169,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
        char *name = dev->dev.bus_id;
        const u32 *reg;
        u64 addr;
-       long magic;
+       int magic;
 
        /*
         * If it's a DCR based device, use 'd' for native DCRs
index 2f54cd81dea571ce82468d82361ae0a67e397f3e..8336deafc624fd7973c9a36e412787f890e8aeb1 100644 (file)
@@ -736,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
        return NULL;
 }
 
-static int
-scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
+                                              unsigned int devfn)
 {
-       const unsigned int *reg;
-       u8* fdata = (u8*)data;
-       
-       reg = get_property(node, "reg", NULL);
-       if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
-               && ((reg[0] >> 16) & 0xff) == fdata[0])
-               return 1;
-       return 0;
+       struct device_node *np = NULL;
+       const u32 *reg;
+       unsigned int psize;
+
+       while ((np = of_get_next_child(parent, np)) != NULL) {
+               reg = get_property(np, "reg", &psize);
+               if (reg == NULL || psize < 4)
+                       continue;
+               if (((reg[0] >> 8) & 0xff) == devfn)
+                       return np;
+       }
+       return NULL;
 }
 
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+
+static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
 {
-       u8 filter_data[2] = {bus, dev_fn};
+       struct device_node *parent, *np;
+
+       /* Are we a root bus ? */
+       if (bus->self == NULL || bus->parent == NULL) {
+               struct pci_controller *hose = pci_bus_to_hose(bus->number);
+               if (hose == NULL)
+                       return NULL;
+               return of_node_get(hose->arch_data);
+       }
+
+       /* not a root bus, we need to get our parent */
+       parent = scan_OF_for_pci_bus(bus->parent);
+       if (parent == NULL)
+               return NULL;
+
+       /* now iterate for children for a match */
+       np = scan_OF_for_pci_dev(parent, bus->self->devfn);
+       of_node_put(parent);
 
-       return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
+       /* sanity check */
+       if (strcmp(np->type, "pci") != 0)
+               printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n",
+                      np->type, np->full_name);
+
+       return np;
 }
 
 /*
@@ -763,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
 struct device_node *
 pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
 {
-       struct pci_controller *hose;
-       struct device_node *node;
-       int busnr;
+       struct device_node *parent, *np;
 
        if (!have_of)
                return NULL;
-       
-       /* Lookup the hose */
-       busnr = bus->number;
-       hose = pci_bus_to_hose(busnr);
-       if (!hose)
-               return NULL;
 
-       /* Check it has an OF node associated */
-       node = (struct device_node *) hose->arch_data;
-       if (!node)
+       DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
+       parent = scan_OF_for_pci_bus(bus);
+       if (parent == NULL)
                return NULL;
-
-       /* Fixup bus number according to what OF think it is. */
-#ifdef CONFIG_PPC_PMAC
-       /* The G5 need a special case here. Basically, we don't remap all
-        * busses on it so we don't create the pci-OF-map. However, we do
-        * remap the AGP bus and so have to deal with it. A future better
-        * fix has to be done by making the remapping per-host and always
-        * filling the pci_to_OF map. --BenH
+       DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");
+       np = scan_OF_for_pci_dev(parent, devfn);
+       of_node_put(parent);
+       DBG(" result is %s\n", np ? np->full_name : "<NULL>");
+
+       /* XXX most callers don't release the returned node
+        * mostly because ppc64 doesn't increase the refcount,
+        * we need to fix that.
         */
-       if (machine_is(powermac) && busnr >= 0xf0)
-               busnr -= 0xf0;
-       else
-#endif
-       if (pci_to_OF_bus_map)
-               busnr = pci_to_OF_bus_map[busnr];
-       if (busnr == 0xff)
-               return NULL;
-       
-       /* Now, lookup childs of the hose */
-       return scan_OF_childs_for_device(node->child, busnr, devfn);
+       return np;
 }
 EXPORT_SYMBOL(pci_busdev_to_OF_node);
 
@@ -1544,7 +1552,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
 
 
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -1556,7 +1564,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
@@ -1624,9 +1634,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
-               (unsigned long long)rp->start, prot);
-
        return __pgprot(prot);
 }
 
@@ -1695,7 +1702,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state,
                        int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1808,22 +1815,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = (void __iomem *)_IO_BASE - hose->io_base_virt
-                       + hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
-                 int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name)
 {
        res->start = start;
        res->end = end;
index 6fa9a0a5c8dbb7f0a700c0e88048e7037caaa63f..a6b7692c72690bc592e1429d08a921e23f9ed946 100644 (file)
@@ -682,7 +682,7 @@ int pci_proc_domain(struct pci_bus *bus)
  * Returns negative error code on failure, zero on success.
  */
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -694,7 +694,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
@@ -762,9 +764,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
-
        return __pgprot(prot);
 }
 
@@ -832,7 +831,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1333,20 +1332,41 @@ EXPORT_SYMBOL(pci_read_irq_line);
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = pci_io_base - (unsigned long)hose->io_base_virt +
-                       hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - pci_io_base;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
 struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
index 9179f0739ea2c3afb952fad59fa21017bd1fc403..95776b6af4e2892513a70d118a73e70b39d278f9 100644 (file)
@@ -208,7 +208,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
 #endif /* CONFIG_PPC_STD_MMU_32 */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_DCR_NATIVE
 EXPORT_SYMBOL(__mtdcr);
 EXPORT_SYMBOL(__mfdcr);
 #endif
index c18dbe77fdc29863eb5a4f3e57c2f5f62e0f93dc..1fc732a552db87ee7a7d0e9aedc4535fc51a8158 100644 (file)
@@ -804,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
        return of_read_ulong(p, s);
 }
 
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Interpret the ibm,dynamic-memory property in the
+ * /ibm,dynamic-reconfiguration-memory node.
+ * This contains a list of memory blocks along with NUMA affinity
+ * information.
+ */
+static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+{
+       cell_t *dm, *ls;
+       unsigned long l, n;
+       unsigned long base, size, lmb_size, flags;
+
+       ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
+       if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
+               return 0;
+       lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
+
+       dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
+       if (dm == NULL || l < sizeof(cell_t))
+               return 0;
+
+       n = *dm++;      /* number of entries */
+       if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
+               return 0;
+
+       for (; n != 0; --n) {
+               base = dt_mem_next_cell(dt_root_addr_cells, &dm);
+               flags = dm[3];
+               /* skip DRC index, pad, assoc. list index, flags */
+               dm += 4;
+               /* skip this block if the reserved bit is set in flags (0x80)
+                  or if the block is not assigned to this partition (0x8) */
+               if ((flags & 0x80) || !(flags & 0x8))
+                       continue;
+               size = lmb_size;
+               if (iommu_is_off) {
+                       if (base >= 0x80000000ul)
+                               continue;
+                       if ((base + size) > 0x80000000ul)
+                               size = 0x80000000ul - base;
+               }
+               lmb_add(base, size);
+       }
+       lmb_dump_all();
+       return 0;
+}
+#else
+#define early_init_dt_scan_drconf_memory(node) 0
+#endif /* CONFIG_PPC_PSERIES */
 
 static int __init early_init_dt_scan_memory(unsigned long node,
                                            const char *uname, int depth, void *data)
@@ -812,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node,
        cell_t *reg, *endp;
        unsigned long l;
 
+       /* Look for the ibm,dynamic-reconfiguration-memory node */
+       if (depth == 1 &&
+           strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
+               return early_init_dt_scan_drconf_memory(node);
+
        /* We are scanning "memory" nodes only */
        if (type == NULL) {
                /*
index 46cf32670ddb67cab23dfe986e686d7bea0ffbb7..520ef42f642ecca95c2f04ce3a4480fa3f913c33 100644 (file)
@@ -679,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = {
        /* option vector 5: PAPR/OF options */
        3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
-       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
index 387ed0d9ad618b3597a7f0931af169993ba103ee..76b5d7ebdcc681fe0b8f4730300b90bc55827fce 100644 (file)
@@ -303,6 +303,12 @@ int rtas_token(const char *service)
 }
 EXPORT_SYMBOL(rtas_token);
 
+int rtas_service_present(const char *service)
+{
+       return rtas_token(service) != RTAS_UNKNOWN_SERVICE;
+}
+EXPORT_SYMBOL(rtas_service_present);
+
 #ifdef CONFIG_RTAS_ERROR_LOGGING
 /*
  * Return the firmware-specified size of the error log buffer
@@ -810,32 +816,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        return 0;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-/* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
-       /* The token is initialized for real in setup_system() */
-       .token = RTAS_UNKNOWN_SERVICE,
-       .nargs = 0,
-       .nret = 1,
-       .rets = &rtas_stop_self_args.args[0],
-};
-
-void rtas_stop_self(void)
-{
-       struct rtas_args *rtas_args = &rtas_stop_self_args;
-
-       local_irq_disable();
-
-       BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE);
-
-       printk("cpu %u (hwid %u) Ready to die...\n",
-              smp_processor_id(), hard_smp_processor_id());
-       enter_rtas(__pa(rtas_args));
-
-       panic("Alas, I survived.\n");
-}
-#endif
-
 /*
  * Call early during boot, before mem init or bootmem, to retrieve the RTAS
  * informations from the device-tree and allocate the RMO buffer for userland
@@ -880,9 +860,6 @@ void __init rtas_initialize(void)
 #endif
        rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       rtas_stop_self_args.token = rtas_token("stop-self");
-#endif /* CONFIG_HOTPLUG_CPU */
 #ifdef CONFIG_RTAS_ERROR_LOGGING
        rtas_last_error_token = rtas_token("rtas-last-error");
 #endif
index 63ed265b7f0936765a1cc7bc9356404acf679e68..400ab2b946e760964bd164f282ec1f270579ac6a 100644 (file)
@@ -181,6 +181,8 @@ SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
 SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
 SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
 SYSFS_PMCSETUP(purr, SPRN_PURR);
+SYSFS_PMCSETUP(spurr, SPRN_SPURR);
+SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
 static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0);
 static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1);
@@ -194,6 +196,8 @@ static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6);
 static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7);
 static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8);
 static SYSDEV_ATTR(purr, 0600, show_purr, NULL);
+static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
+static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
 
 static void register_cpu_online(unsigned int cpu)
 {
@@ -231,6 +235,12 @@ static void register_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_PURR))
                sysdev_create_file(s, &attr_purr);
+
+       if (cpu_has_feature(CPU_FTR_SPURR))
+               sysdev_create_file(s, &attr_spurr);
+
+       if (cpu_has_feature(CPU_FTR_DSCR))
+               sysdev_create_file(s, &attr_dscr);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -272,6 +282,12 @@ static void unregister_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_PURR))
                sysdev_remove_file(s, &attr_purr);
+
+       if (cpu_has_feature(CPU_FTR_SPURR))
+               sysdev_remove_file(s, &attr_spurr);
+
+       if (cpu_has_feature(CPU_FTR_DSCR))
+               sysdev_remove_file(s, &attr_dscr);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
index 0d4e203fa7a05d90751ff0e7e60cb891f413d6af..535f50665647eb490cdc32fd48223c780d55adfd 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
 #include <linux/backlight.h>
+#include <linux/bug.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -727,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs)
        return -EINVAL;
 }
 
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one.  At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x)     NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
+int is_valid_bugaddr(unsigned long addr)
 {
-       struct bug_entry *bug;
-
-       for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
-               if (bugaddr == bug->bug_addr)
-                       return bug;
-       return module_find_bug(bugaddr);
-}
-
-static int check_bug_trap(struct pt_regs *regs)
-{
-       struct bug_entry *bug;
-       unsigned long addr;
-
-       if (regs->msr & MSR_PR)
-               return 0;       /* not in kernel */
-       addr = regs->nip;       /* address of trap instruction */
-       if (addr < PAGE_OFFSET)
-               return 0;
-       bug = find_bug(regs->nip);
-       if (bug == NULL)
-               return 0;
-       if (bug->line & BUG_WARNING_TRAP) {
-               /* this is a WARN_ON rather than BUG/BUG_ON */
-               printk(KERN_ERR "Badness in %s at %s:%ld\n",
-                      bug->function, bug->file,
-                      bug->line & ~BUG_WARNING_TRAP);
-               dump_stack();
-               return 1;
-       }
-       printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
-              bug->function, bug->file, bug->line);
-
-       return 0;
+       return is_kernel_addr(addr);
 }
 
 void __kprobes program_check_exception(struct pt_regs *regs)
@@ -782,6 +738,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
        unsigned int reason = get_reason(regs);
        extern int do_mathemu(struct pt_regs *regs);
 
+       /* We can now get here via a FP Unavailable exception if the core
+        * has no FPU, in that case no reason flags will be set */
 #ifdef CONFIG_MATH_EMULATION
        /* (reason & REASON_ILLEGAL) would be the obvious thing here,
         * but there seems to be a hardware bug on the 405GP (RevD)
@@ -808,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
                        return;
                if (debugger_bpt(regs))
                        return;
-               if (check_bug_trap(regs)) {
+
+               if (!(regs->msr & MSR_PR) &&  /* not user-mode */
+                   report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
                        regs->nip += 4;
                        return;
                }
index 04b98671a0608d6ced7470712291bde24d3e01ac..04b8e71bf5b0087a814fba70bd47dce22eda717f 100644 (file)
@@ -62,11 +62,7 @@ SECTIONS
                __stop___ex_table = .;
        }
 
-       __bug_table : {
-               __start___bug_table = .;
-               *(__bug_table)
-               __stop___bug_table = .;
-       }
+       BUG_TABLE
 
 /*
  * Init sections discarded at runtime
index 9da01dc8cfd9d3fc0722de803d7cfbfb9e0ab573..262790910ff23900f5bef2ab057feb4ff5a4e636 100644 (file)
@@ -295,6 +295,63 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
        return lmb_end_of_DRAM() - start;
 }
 
+/*
+ * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
+ * node.  This assumes n_mem_{addr,size}_cells have been set.
+ */
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+       const unsigned int *lm, *dm, *aa;
+       unsigned int ls, ld, la;
+       unsigned int n, aam, aalen;
+       unsigned long lmb_size, size;
+       int nid, default_nid = 0;
+       unsigned int start, ai, flags;
+
+       lm = get_property(memory, "ibm,lmb-size", &ls);
+       dm = get_property(memory, "ibm,dynamic-memory", &ld);
+       aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+       if (!lm || !dm || !aa ||
+           ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
+           la < 2 * sizeof(unsigned int))
+               return;
+
+       lmb_size = read_n_cells(n_mem_size_cells, &lm);
+       n = *dm++;              /* number of LMBs */
+       aam = *aa++;            /* number of associativity lists */
+       aalen = *aa++;          /* length of each associativity list */
+       if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) ||
+           la < (aam * aalen + 2) * sizeof(unsigned int))
+               return;
+
+       for (; n != 0; --n) {
+               start = read_n_cells(n_mem_addr_cells, &dm);
+               ai = dm[2];
+               flags = dm[3];
+               dm += 4;
+               /* 0x80 == reserved, 0x8 = assigned to us */
+               if ((flags & 0x80) || !(flags & 0x8))
+                       continue;
+               nid = default_nid;
+               /* flags & 0x40 means associativity index is invalid */
+               if (min_common_depth > 0 && min_common_depth <= aalen &&
+                   (flags & 0x40) == 0 && ai < aam) {
+                       /* this is like of_node_to_nid_single */
+                       nid = aa[ai * aalen + min_common_depth - 1];
+                       if (nid == 0xffff || nid >= MAX_NUMNODES)
+                               nid = default_nid;
+               }
+               node_set_online(nid);
+
+               size = numa_enforce_memory_limit(start, lmb_size);
+               if (!size)
+                       continue;
+
+               add_active_range(nid, start >> PAGE_SHIFT,
+                                (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
+       }
+}
+
 static int __init parse_numa_properties(void)
 {
        struct device_node *cpu = NULL;
@@ -385,6 +442,14 @@ new_range:
                        goto new_range;
        }
 
+       /*
+        * Now do the same thing for each LMB listed in the ibm,dynamic-memory
+        * property in the ibm,dynamic-reconfiguration-memory node.
+        */
+       memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+       if (memory)
+               parse_drconf_memory(memory);
+
        return 0;
 }
 
index a375c15b4315b502517a9d65510fc5eeb509bc84..eaff71e74fb0f8a783465715f73560c877a81c69 100644 (file)
@@ -40,8 +40,6 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
 #include <asm/of_platform.h>
 
 #include <asm/mpc52xx.h>
index 616a0a3fd0e2ad9c10330590b3d5c0a785e2317d..70e0d968d30f9e5edd77efdc7ce01451586440e3 100644 (file)
@@ -115,6 +115,7 @@ static struct sysdev_attribute attr_spu_temperature = {
 
 static struct attribute *spu_attributes[] = {
        &attr_spu_temperature.attr,
+       NULL,
 };
 
 static struct attribute_group spu_attribute_group = {
@@ -135,6 +136,7 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
 static struct attribute *ppe_attributes[] = {
        &attr_ppe_temperature0.attr,
        &attr_ppe_temperature1.attr,
+       NULL,
 };
 
 static struct attribute_group ppe_attribute_group = {
index 99c612025e8fa824dc35cb34741fc6672f6a2e39..d04ae1671e6ce5d40f413f820efeb645169d3ba2 100644 (file)
@@ -382,11 +382,14 @@ static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int __init cbe_init_pm_irq(void)
+static int __init cbe_init_pm_irq(void)
 {
        unsigned int irq;
        int rc, node;
 
+       if (!machine_is(cell))
+               return 0;
+
        for_each_node(node) {
                irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
                                               (node << IIC_IRQ_NODE_SHIFT));
index 26945c491f6b21bd7783bff75478df20a9c9aafe..725e19561159dd60bf492d0d87816f3f76767e51 100644 (file)
@@ -147,7 +147,7 @@ static int spufs_arch_notes_size(void)
        struct fdtable *fdt = files_fdtable(current->files);
        int size = 0, fd;
 
-       for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
+       for (fd = 0; fd < fdt->max_fds; fd++) {
                if (FD_ISSET(fd, fdt->open_fds)) {
                        struct file *file = fcheck(fd);
 
index 3a32deda765dab3487e1174467f923ceede19fc6..3f6a69f67195a0e7172a072925d6461eedc388fa 100644 (file)
@@ -562,7 +562,7 @@ void __init maple_pci_init(void)
        for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
                if (np->name == NULL)
                        continue;
-               if (strcmp(np->name, "pci") == 0) {
+               if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) {
                        if (add_bridge(np) == 0)
                                of_node_get(np);
                }
index 094989d50babaf0bdfe46db5e4b3ab1cd1531924..f12d5c69e74dea275d772308cdcf311da4f54956 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/of_device.h>
 #include <asm/lmb.h>
 #include <asm/mpic.h>
+#include <asm/rtas.h>
 #include <asm/udbg.h>
 
 #include "maple.h"
@@ -166,6 +167,16 @@ struct smp_ops_t maple_smp_ops = {
 };
 #endif /* CONFIG_SMP */
 
+static void __init maple_use_rtas_reboot_and_halt_if_present(void)
+{
+       if (rtas_service_present("system-reboot") &&
+           rtas_service_present("power-off")) {
+               ppc_md.restart = rtas_restart;
+               ppc_md.power_off = rtas_power_off;
+               ppc_md.halt = rtas_halt;
+       }
+}
+
 void __init maple_setup_arch(void)
 {
        /* init to some ~sane value until calibrate_delay() runs */
@@ -181,6 +192,7 @@ void __init maple_setup_arch(void)
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
+       maple_use_rtas_reboot_and_halt_if_present();
 
        printk(KERN_DEBUG "Using native/NAP idle loop\n");
 }
index 451bfcd5502e537549937f989bc5b99795d1866c..de52ec4e9e586c7d11e088587beddfb669ce4a6e 100644 (file)
@@ -40,4 +40,15 @@ config PS3_USE_LPAR_ADDR
 
          If you have any doubt, choose the default y.
 
+config PS3_VUART
+       depends on PPC_PS3
+       bool "PS3 Virtual UART support"
+       default y
+       help
+         Include support for the PS3 Virtual UART.
+
+         This support is required for several system services
+         including the System Manager and AV Settings.  In
+         general, all users will say Y.
+
 endmenu
index 997243a91be8778b77b95619e20f385527c7c9ef..69590fbf83daef9ba3a246c7e9f9a14b0d8261b5 100644 (file)
@@ -10,6 +10,8 @@ obj-$(CONFIG_XICS)    += xics.o
 obj-$(CONFIG_SCANLOG)  += scanlog.o
 obj-$(CONFIG_EEH)      += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
 
+obj-$(CONFIG_HOTPLUG_CPU)      += hotplug-cpu.o
+
 obj-$(CONFIG_HVC_CONSOLE)      += hvconsole.o
 obj-$(CONFIG_HVCS)             += hvcserver.o
 obj-$(CONFIG_HCALL_STATS)      += hvCall_inst.o
index 3c2d63ebf787fae9e60e3c98713c36d3e1590d8f..da6e5362e7cd8f13f802729e957538cc491e41b3 100644 (file)
@@ -337,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
                        printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
                                pdn->eeh_check_count);
                        dump_stack();
+                       msleep(5000);
                        
                        /* re-read the slot reset state */
                        if (read_slot_reset_state(pdn, rets) != 0)
index c2bc9904f1cb9af0369b11ceb76bae5fcf12f619..cbd6b0711ab450f1c306930d1ebdb50e3834201d 100644 (file)
@@ -170,14 +170,19 @@ 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 (!driver->err_handler)
-               return;
-       if (!driver->err_handler->resume)
+
+       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
+               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+               enable_irq(dev->irq);
+       }
+       if (!driver->err_handler ||
+           !driver->err_handler->resume)
                return;
 
        driver->err_handler->resume(dev);
@@ -407,6 +412,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
                if (rc)
                        result = PCI_ERS_RESULT_NEED_RESET;
+               else
+                       result = PCI_ERS_RESULT_RECOVERED;
        }
 
        /* If any device has a hard failure, then shut off everything. */
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
new file mode 100644 (file)
index 0000000..f460b9c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * pseries CPU Hotplug infrastructure.
+ *
+ * Split out from arch/powerpc/platforms/pseries/setup.c
+ *  arch/powerpc/kernel/rtas.c, and arch/powerpc/platforms/pseries/smp.c
+ *
+ * Peter Bergner, IBM  March 2001.
+ * Copyright (C) 2001 IBM.
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ * Plus various changes from other IBM teams...
+ *
+ * Copyright (C) 2006 Michael Ellerman, IBM Corporation
+ *
+ *      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/delay.h>
+#include <linux/cpu.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/firmware.h>
+#include <asm/machdep.h>
+#include <asm/vdso_datapage.h>
+#include <asm/pSeries_reconfig.h>
+#include "xics.h"
+
+/* This version can't take the spinlock, because it never returns */
+static struct rtas_args rtas_stop_self_args = {
+       .token = RTAS_UNKNOWN_SERVICE,
+       .nargs = 0,
+       .nret = 1,
+       .rets = &rtas_stop_self_args.args[0],
+};
+
+static void rtas_stop_self(void)
+{
+       struct rtas_args *args = &rtas_stop_self_args;
+
+       local_irq_disable();
+
+       BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+
+       printk("cpu %u (hwid %u) Ready to die...\n",
+              smp_processor_id(), hard_smp_processor_id());
+       enter_rtas(__pa(args));
+
+       panic("Alas, I survived.\n");
+}
+
+static void pseries_mach_cpu_die(void)
+{
+       local_irq_disable();
+       idle_task_exit();
+       xics_teardown_cpu(0);
+       rtas_stop_self();
+       /* Should never get here... */
+       BUG();
+       for(;;);
+}
+
+static int qcss_tok;   /* query-cpu-stopped-state token */
+
+/* Get state of physical CPU.
+ * Return codes:
+ *     0       - The processor is in the RTAS stopped state
+ *     1       - stop-self is in progress
+ *     2       - The processor is not in the RTAS stopped state
+ *     -1      - Hardware Error
+ *     -2      - Hardware Busy, Try again later.
+ */
+static int query_cpu_stopped(unsigned int pcpu)
+{
+       int cpu_status, status;
+
+       status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
+       if (status != 0) {
+               printk(KERN_ERR
+                      "RTAS query-cpu-stopped-state failed: %i\n", status);
+               return status;
+       }
+
+       return cpu_status;
+}
+
+static int pseries_cpu_disable(void)
+{
+       int cpu = smp_processor_id();
+
+       cpu_clear(cpu, cpu_online_map);
+       vdso_data->processorCount--;
+
+       /*fix boot_cpuid here*/
+       if (cpu == boot_cpuid)
+               boot_cpuid = any_online_cpu(cpu_online_map);
+
+       /* FIXME: abstract this to not be platform specific later on */
+       xics_migrate_irqs_away();
+       return 0;
+}
+
+static void pseries_cpu_die(unsigned int cpu)
+{
+       int tries;
+       int cpu_status;
+       unsigned int pcpu = get_hard_smp_processor_id(cpu);
+
+       for (tries = 0; tries < 25; tries++) {
+               cpu_status = query_cpu_stopped(pcpu);
+               if (cpu_status == 0 || cpu_status == -1)
+                       break;
+               msleep(200);
+       }
+       if (cpu_status != 0) {
+               printk("Querying DEAD? cpu %i (%i) shows %i\n",
+                      cpu, pcpu, cpu_status);
+       }
+
+       /* Isolation and deallocation are definatly done by
+        * drslot_chrp_cpu.  If they were not they would be
+        * done here.  Change isolate state to Isolate and
+        * change allocation-state to Unusable.
+        */
+       paca[cpu].cpu_start = 0;
+}
+
+/*
+ * Update cpu_present_map and paca(s) for a new cpu node.  The wrinkle
+ * here is that a cpu device node may represent up to two logical cpus
+ * in the SMT case.  We must honor the assumption in other code that
+ * the logical ids for sibling SMT threads x and y are adjacent, such
+ * that x^1 == y and y^1 == x.
+ */
+static int pseries_add_processor(struct device_node *np)
+{
+       unsigned int cpu;
+       cpumask_t candidate_map, tmp = CPU_MASK_NONE;
+       int err = -ENOSPC, len, nthreads, i;
+       const u32 *intserv;
+
+       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       if (!intserv)
+               return 0;
+
+       nthreads = len / sizeof(u32);
+       for (i = 0; i < nthreads; i++)
+               cpu_set(i, tmp);
+
+       lock_cpu_hotplug();
+
+       BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
+
+       /* Get a bitmap of unoccupied slots. */
+       cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
+       if (cpus_empty(candidate_map)) {
+               /* If we get here, it most likely means that NR_CPUS is
+                * less than the partition's max processors setting.
+                */
+               printk(KERN_ERR "Cannot add cpu %s; this system configuration"
+                      " supports %d logical cpus.\n", np->full_name,
+                      cpus_weight(cpu_possible_map));
+               goto out_unlock;
+       }
+
+       while (!cpus_empty(tmp))
+               if (cpus_subset(tmp, candidate_map))
+                       /* Found a range where we can insert the new cpu(s) */
+                       break;
+               else
+                       cpus_shift_left(tmp, tmp, nthreads);
+
+       if (cpus_empty(tmp)) {
+               printk(KERN_ERR "Unable to find space in cpu_present_map for"
+                      " processor %s with %d thread(s)\n", np->name,
+                      nthreads);
+               goto out_unlock;
+       }
+
+       for_each_cpu_mask(cpu, tmp) {
+               BUG_ON(cpu_isset(cpu, cpu_present_map));
+               cpu_set(cpu, cpu_present_map);
+               set_hard_smp_processor_id(cpu, *intserv++);
+       }
+       err = 0;
+out_unlock:
+       unlock_cpu_hotplug();
+       return err;
+}
+
+/*
+ * Update the present map for a cpu node which is going away, and set
+ * the hard id in the paca(s) to -1 to be consistent with boot time
+ * convention for non-present cpus.
+ */
+static void pseries_remove_processor(struct device_node *np)
+{
+       unsigned int cpu;
+       int len, nthreads, i;
+       const u32 *intserv;
+
+       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       if (!intserv)
+               return;
+
+       nthreads = len / sizeof(u32);
+
+       lock_cpu_hotplug();
+       for (i = 0; i < nthreads; i++) {
+               for_each_present_cpu(cpu) {
+                       if (get_hard_smp_processor_id(cpu) != intserv[i])
+                               continue;
+                       BUG_ON(cpu_online(cpu));
+                       cpu_clear(cpu, cpu_present_map);
+                       set_hard_smp_processor_id(cpu, -1);
+                       break;
+               }
+               if (cpu == NR_CPUS)
+                       printk(KERN_WARNING "Could not find cpu to remove "
+                              "with physical id 0x%x\n", intserv[i]);
+       }
+       unlock_cpu_hotplug();
+}
+
+static int pseries_smp_notifier(struct notifier_block *nb,
+                               unsigned long action, void *node)
+{
+       int err = NOTIFY_OK;
+
+       switch (action) {
+       case PSERIES_RECONFIG_ADD:
+               if (pseries_add_processor(node))
+                       err = NOTIFY_BAD;
+               break;
+       case PSERIES_RECONFIG_REMOVE:
+               pseries_remove_processor(node);
+               break;
+       default:
+               err = NOTIFY_DONE;
+               break;
+       }
+       return err;
+}
+
+static struct notifier_block pseries_smp_nb = {
+       .notifier_call = pseries_smp_notifier,
+};
+
+static int __init pseries_cpu_hotplug_init(void)
+{
+       rtas_stop_self_args.token = rtas_token("stop-self");
+       qcss_tok = rtas_token("query-cpu-stopped-state");
+
+       if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+                       qcss_tok == RTAS_UNKNOWN_SERVICE) {
+               printk(KERN_INFO "CPU Hotplug not supported by firmware "
+                               "- disabling.\n");
+               return 0;
+       }
+
+       ppc_md.cpu_die = pseries_mach_cpu_die;
+       smp_ops->cpu_disable = pseries_cpu_disable;
+       smp_ops->cpu_die = pseries_cpu_die;
+
+       /* Processors can be added/removed only on LPAR */
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               pSeries_reconfig_notifier_register(&pseries_smp_nb);
+
+       return 0;
+}
+arch_initcall(pseries_cpu_hotplug_init);
index 0dc2548ca9bcdd45bebf827db6aa2fe813b20bb0..042ecae107ac89066c5596ab0ccafe58161539d9 100644 (file)
@@ -347,21 +347,6 @@ static int __init pSeries_init_panel(void)
 }
 arch_initcall(pSeries_init_panel);
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void pSeries_mach_cpu_die(void)
-{
-       local_irq_disable();
-       idle_task_exit();
-       xics_teardown_cpu(0);
-       rtas_stop_self();
-       /* Should never get here... */
-       BUG();
-       for(;;);
-}
-#else
-#define pSeries_mach_cpu_die NULL
-#endif
-
 static int pseries_set_dabr(unsigned long dabr)
 {
        return plpar_hcall_norets(H_SET_DABR, dabr);
@@ -437,19 +422,14 @@ static int __init pSeries_probe_hypertas(unsigned long node,
        if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
                powerpc_firmware_features |= FW_FEATURE_LPAR;
 
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               hpte_init_lpar();
-       else
-               hpte_init_native();
-
        return 1;
 }
 
 static int __init pSeries_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
-       char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
-                                         "device_type", NULL);
+       char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
+
        if (dtype == NULL)
                return 0;
        if (strcmp(dtype, "chrp"))
@@ -467,6 +447,11 @@ static int __init pSeries_probe(void)
        /* Now try to figure out if we are running on LPAR */
        of_scan_flat_dt(pSeries_probe_hypertas, NULL);
 
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               hpte_init_lpar();
+       else
+               hpte_init_native();
+
        DBG("Machine is%s LPAR !\n",
            (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
 
@@ -561,7 +546,6 @@ define_machine(pseries) {
        .power_off              = rtas_power_off,
        .halt                   = rtas_halt,
        .panic                  = rtas_os_term,
-       .cpu_die                = pSeries_mach_cpu_die,
        .get_boot_time          = rtas_get_boot_time,
        .get_rtc_time           = rtas_get_rtc_time,
        .set_rtc_time           = rtas_set_rtc_time,
index c6624b8a0e774b2aca2e3dab6fc268785f623318..4408518eaebe4afe76d6a1b3f354a4a6cc0a0421 100644 (file)
@@ -64,197 +64,6 @@ static cpumask_t of_spin_map;
 
 extern void generic_secondary_smp_init(unsigned long);
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* Get state of physical CPU.
- * Return codes:
- *     0       - The processor is in the RTAS stopped state
- *     1       - stop-self is in progress
- *     2       - The processor is not in the RTAS stopped state
- *     -1      - Hardware Error
- *     -2      - Hardware Busy, Try again later.
- */
-static int query_cpu_stopped(unsigned int pcpu)
-{
-       int cpu_status;
-       int status, qcss_tok;
-
-       qcss_tok = rtas_token("query-cpu-stopped-state");
-       if (qcss_tok == RTAS_UNKNOWN_SERVICE)
-               return -1;
-       status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
-       if (status != 0) {
-               printk(KERN_ERR
-                      "RTAS query-cpu-stopped-state failed: %i\n", status);
-               return status;
-       }
-
-       return cpu_status;
-}
-
-static int pSeries_cpu_disable(void)
-{
-       int cpu = smp_processor_id();
-
-       cpu_clear(cpu, cpu_online_map);
-       vdso_data->processorCount--;
-
-       /*fix boot_cpuid here*/
-       if (cpu == boot_cpuid)
-               boot_cpuid = any_online_cpu(cpu_online_map);
-
-       /* FIXME: abstract this to not be platform specific later on */
-       xics_migrate_irqs_away();
-       return 0;
-}
-
-static void pSeries_cpu_die(unsigned int cpu)
-{
-       int tries;
-       int cpu_status;
-       unsigned int pcpu = get_hard_smp_processor_id(cpu);
-
-       for (tries = 0; tries < 25; tries++) {
-               cpu_status = query_cpu_stopped(pcpu);
-               if (cpu_status == 0 || cpu_status == -1)
-                       break;
-               msleep(200);
-       }
-       if (cpu_status != 0) {
-               printk("Querying DEAD? cpu %i (%i) shows %i\n",
-                      cpu, pcpu, cpu_status);
-       }
-
-       /* Isolation and deallocation are definatly done by
-        * drslot_chrp_cpu.  If they were not they would be
-        * done here.  Change isolate state to Isolate and
-        * change allocation-state to Unusable.
-        */
-       paca[cpu].cpu_start = 0;
-}
-
-/*
- * Update cpu_present_map and paca(s) for a new cpu node.  The wrinkle
- * here is that a cpu device node may represent up to two logical cpus
- * in the SMT case.  We must honor the assumption in other code that
- * the logical ids for sibling SMT threads x and y are adjacent, such
- * that x^1 == y and y^1 == x.
- */
-static int pSeries_add_processor(struct device_node *np)
-{
-       unsigned int cpu;
-       cpumask_t candidate_map, tmp = CPU_MASK_NONE;
-       int err = -ENOSPC, len, nthreads, i;
-       const u32 *intserv;
-
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
-       if (!intserv)
-               return 0;
-
-       nthreads = len / sizeof(u32);
-       for (i = 0; i < nthreads; i++)
-               cpu_set(i, tmp);
-
-       lock_cpu_hotplug();
-
-       BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
-
-       /* Get a bitmap of unoccupied slots. */
-       cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
-       if (cpus_empty(candidate_map)) {
-               /* If we get here, it most likely means that NR_CPUS is
-                * less than the partition's max processors setting.
-                */
-               printk(KERN_ERR "Cannot add cpu %s; this system configuration"
-                      " supports %d logical cpus.\n", np->full_name,
-                      cpus_weight(cpu_possible_map));
-               goto out_unlock;
-       }
-
-       while (!cpus_empty(tmp))
-               if (cpus_subset(tmp, candidate_map))
-                       /* Found a range where we can insert the new cpu(s) */
-                       break;
-               else
-                       cpus_shift_left(tmp, tmp, nthreads);
-
-       if (cpus_empty(tmp)) {
-               printk(KERN_ERR "Unable to find space in cpu_present_map for"
-                      " processor %s with %d thread(s)\n", np->name,
-                      nthreads);
-               goto out_unlock;
-       }
-
-       for_each_cpu_mask(cpu, tmp) {
-               BUG_ON(cpu_isset(cpu, cpu_present_map));
-               cpu_set(cpu, cpu_present_map);
-               set_hard_smp_processor_id(cpu, *intserv++);
-       }
-       err = 0;
-out_unlock:
-       unlock_cpu_hotplug();
-       return err;
-}
-
-/*
- * Update the present map for a cpu node which is going away, and set
- * the hard id in the paca(s) to -1 to be consistent with boot time
- * convention for non-present cpus.
- */
-static void pSeries_remove_processor(struct device_node *np)
-{
-       unsigned int cpu;
-       int len, nthreads, i;
-       const u32 *intserv;
-
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
-       if (!intserv)
-               return;
-
-       nthreads = len / sizeof(u32);
-
-       lock_cpu_hotplug();
-       for (i = 0; i < nthreads; i++) {
-               for_each_present_cpu(cpu) {
-                       if (get_hard_smp_processor_id(cpu) != intserv[i])
-                               continue;
-                       BUG_ON(cpu_online(cpu));
-                       cpu_clear(cpu, cpu_present_map);
-                       set_hard_smp_processor_id(cpu, -1);
-                       break;
-               }
-               if (cpu == NR_CPUS)
-                       printk(KERN_WARNING "Could not find cpu to remove "
-                              "with physical id 0x%x\n", intserv[i]);
-       }
-       unlock_cpu_hotplug();
-}
-
-static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
-       int err = NOTIFY_OK;
-
-       switch (action) {
-       case PSERIES_RECONFIG_ADD:
-               if (pSeries_add_processor(node))
-                       err = NOTIFY_BAD;
-               break;
-       case PSERIES_RECONFIG_REMOVE:
-               pSeries_remove_processor(node);
-               break;
-       default:
-               err = NOTIFY_DONE;
-               break;
-       }
-       return err;
-}
-
-static struct notifier_block pSeries_smp_nb = {
-       .notifier_call = pSeries_smp_notifier,
-};
-
-#endif /* CONFIG_HOTPLUG_CPU */
-
 /**
  * smp_startup_cpu() - start the given cpu
  *
@@ -422,15 +231,6 @@ static void __init smp_init_pseries(void)
 
        DBG(" -> smp_init_pSeries()\n");
 
-#ifdef CONFIG_HOTPLUG_CPU
-       smp_ops->cpu_disable = pSeries_cpu_disable;
-       smp_ops->cpu_die = pSeries_cpu_die;
-
-       /* Processors can be added/removed only on LPAR */
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               pSeries_reconfig_notifier_register(&pSeries_smp_nb);
-#endif
-
        /* Mark threads which are still spinning in hold loops. */
        if (cpu_has_feature(CPU_FTR_SMT)) {
                for_each_present_cpu(i) { 
index 6cc34597a620202e901927359bf9207664ffb0a8..04d4917eb3035c4140d184e1c740b6fc9eb535cd 100644 (file)
@@ -5,7 +5,8 @@ endif
 obj-$(CONFIG_MPIC)             += mpic.o
 obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)       += grackle.o
-obj-$(CONFIG_PPC_DCR)          += dcr.o dcr-low.o
+obj-$(CONFIG_PPC_DCR)          += dcr.o
+obj-$(CONFIG_PPC_DCR_NATIVE)   += dcr-low.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
diff --git a/arch/powerpc/sysdev/dcr.S b/arch/powerpc/sysdev/dcr.S
deleted file mode 100644 (file)
index 2078f39..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * "Indirect" DCR access
- *
- * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.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.
- */
-
-#include <asm/ppc_asm.h>
-#include <asm/processor.h>
-
-#define DCR_ACCESS_PROLOG(table) \
-       rlwinm  r3,r3,4,18,27;   \
-       lis     r5,table@h;      \
-       ori     r5,r5,table@l;   \
-       add     r3,r3,r5;        \
-       mtctr   r3;              \
-       bctr
-
-_GLOBAL(__mfdcr)
-       DCR_ACCESS_PROLOG(__mfdcr_table)
-
-_GLOBAL(__mtdcr)
-       DCR_ACCESS_PROLOG(__mtdcr_table)
-
-__mfdcr_table:
-       mfdcr  r3,0; blr
-__mtdcr_table:
-       mtdcr  0,r4; blr
-
-dcr     = 1
-        .rept   1023
-       mfdcr   r3,dcr; blr
-       mtdcr   dcr,r4; blr
-       dcr     = dcr + 1
-       .endr
index 6995f51b94882bdcf55815572c305d42516e4771..74e48d94f27ced66c0ed03fad91644a5cdb26222 100644 (file)
@@ -223,23 +223,15 @@ static void qe_ic_mask_irq(unsigned int virq)
        qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
                    temp & ~qe_ic_info[src].mask);
 
-       spin_unlock_irqrestore(&qe_ic_lock, flags);
-}
-
-static void qe_ic_mask_irq_and_ack(unsigned int virq)
-{
-       struct qe_ic *qe_ic = qe_ic_from_irq(virq);
-       unsigned int src = virq_to_hw(virq);
-       unsigned long flags;
-       u32 temp;
-
-       spin_lock_irqsave(&qe_ic_lock, flags);
-
-       temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
-       qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
-                   temp & ~qe_ic_info[src].mask);
-
-       /* There is nothing to do for ack here, ack is handled in ISR */
+       /* Flush the above write before enabling interrupts; otherwise,
+        * spurious interrupts will sometimes happen.  To be 100% sure
+        * that the write has reached the device before interrupts are
+        * enabled, the mask register would have to be read back; however,
+        * this is not required for correctness, only to avoid wasting
+        * time on a large number of spurious interrupts.  In testing,
+        * a sync reduced the observed spurious interrupts to zero.
+        */
+       mb();
 
        spin_unlock_irqrestore(&qe_ic_lock, flags);
 }
@@ -248,7 +240,7 @@ static struct irq_chip qe_ic_irq_chip = {
        .typename = " QEIC  ",
        .unmask = qe_ic_unmask_irq,
        .mask = qe_ic_mask_irq,
-       .mask_ack = qe_ic_mask_irq_and_ack,
+       .mask_ack = qe_ic_mask_irq,
 };
 
 static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
@@ -331,34 +323,22 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
        return irq_linear_revmap(qe_ic->irqhost, irq);
 }
 
-/* FIXME: We mask all the QE Low interrupts while handling.  We should
- * let other interrupt come in, but BAD interrupts are generated */
 void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
 {
        struct qe_ic *qe_ic = desc->handler_data;
-       struct irq_chip *chip = irq_desc[irq].chip;
-
        unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
 
-       chip->mask_ack(irq);
        if (cascade_irq != NO_IRQ)
                generic_handle_irq(cascade_irq);
-       chip->unmask(irq);
 }
 
-/* FIXME: We mask all the QE High interrupts while handling.  We should
- * let other interrupt come in, but BAD interrupts are generated */
 void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
 {
        struct qe_ic *qe_ic = desc->handler_data;
-       struct irq_chip *chip = irq_desc[irq].chip;
-
        unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
 
-       chip->mask_ack(irq);
        if (cascade_irq != NO_IRQ)
                generic_handle_irq(cascade_irq);
-       chip->unmask(irq);
 }
 
 void __init qe_ic_init(struct device_node *node, unsigned int flags)
index bf5b3f10e6c600099011cab1ab9f0ccbd221a635..c855a3b298a3f253af247c949db8813622b47ba9 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 static int __init powerpc_flash_init(void)
 {
index a34ed49e0356c418a81fa5cfc85e0f47c0cd84a3..77540a2f77040734396570889e6127230d965404 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/bug.h>
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
@@ -35,7 +36,6 @@
 #include <asm/cputable.h>
 #include <asm/rtas.h>
 #include <asm/sstep.h>
-#include <asm/bug.h>
 #include <asm/irq_regs.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
@@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp)
 
 static void print_bug_trap(struct pt_regs *regs)
 {
-       struct bug_entry *bug;
+       const struct bug_entry *bug;
        unsigned long addr;
 
        if (regs->msr & MSR_PR)
@@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs)
        bug = find_bug(regs->nip);
        if (bug == NULL)
                return;
-       if (bug->line & BUG_WARNING_TRAP)
+       if (is_warning_bug(bug))
                return;
 
-       printf("kernel BUG in %s at %s:%d!\n",
-              bug->function, bug->file, (unsigned int)bug->line);
+       printf("kernel BUG at %s:%u!\n",
+              bug->file, bug->line);
 }
 
 void excprint(struct pt_regs *fp)
index 63808e01cb0b7cc51ea75c20885c630d8ef63ea4..5e723c4c2571b0a3dc886032a92681a9927b9d7c 100644 (file)
@@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
 
 
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = hose->io_base_virt - ___IO_BASE;
@@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state,
                        int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
-                 int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name)
 {
        res->start = start;
        res->end = end;
index 8e24c40662e301fc10b65e5c3aca02210f62ab67..3aa3b885ab36ae4fd9575d44e8a7691c5ad03e3e 100644 (file)
@@ -479,7 +479,7 @@ config SH_CLK_MD
        int "CPU Mode Pin Setting"
        depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
        help
-         MD2 - MD0 Setting.
+         MD2 - MD0 pin setting.
 
 menu "CPU Frequency scaling"
 
@@ -580,18 +580,6 @@ config NR_CPUS
 
 source "kernel/Kconfig.preempt"
 
-config CPU_HAS_SR_RB
-       bool "CPU has SR.RB"
-       depends on CPU_SH3 || CPU_SH4
-       default y
-       help
-         This will enable the use of SR.RB register bank usage. Processors
-         that are lacking this bit must have another method in place for
-         accomplishing what is taken care of by the banked registers.
-
-         See <file:Documentation/sh/register-banks.txt> for further
-         information on SR.RB and register banking in the kernel in general.
-
 config NODES_SHIFT
        int
        default "1"
index 66a25ef4ef1b8bf233e7936f049c91617933596f..87902e0298e29c805a4cf86d398f600c1c128e70 100644 (file)
@@ -31,7 +31,8 @@ config EARLY_SCIF_CONSOLE_PORT
        hex "SCIF port for early console"
        depends on EARLY_SCIF_CONSOLE
        default "0xffe00000" if CPU_SUBTYPE_SH7780
-       default "0xfffe9800" if CPU_SUBTYPE_SH72060
+       default "0xfffe9800" if CPU_SUBTYPE_SH7206
+       default "0xf8420000" if CPU_SUBTYPE_SH7619
        default "0xffe80000" if CPU_SH4
 
 config EARLY_PRINTK
index d10bba5e1074bef182503c598125ef0fa963a7d8..c1dbef21263430f68ba594d2b3d893063732cc11 100644 (file)
@@ -179,7 +179,7 @@ maketools:  include/linux/version.h FORCE
 
 all: zImage
 
-zImage: vmlinux
+zImage uImage uImage.srec vmlinux.srec: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 compressed: zImage
@@ -190,5 +190,8 @@ archclean:
 CLEAN_FILES += include/asm-sh/machtypes.h
 
 define archhelp
-       @echo '  zImage                    - Compressed kernel image (arch/sh/boot/zImage)'
+       @echo '* zImage                    - Compressed kernel image'
+       @echo '  vmlinux.srec              - Create an ELF S-record'
+       @echo '  uImage                    - Create a bootable image for U-Boot'
+       @echo '  uImage.srec               - Create an S-record for U-Boot'
 endef
index 8f2e1c68b90fb7c61f9f25f6321f272e54ea5c46..3eba6d086d7ff8033011776faf90220e2c2553d1 100644 (file)
@@ -16,8 +16,8 @@
  */
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <asm/io.h>
-#include <asm/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
 #include <asm/landisk/iodata_landisk.h>
 
 static void enable_landisk_irq(unsigned int irq);
index 3fb0c5f5b23a3b72c620b8a0a4fe60bb4d044b41..27da88486f73bb4bf84aab19787a28ce6ac68702 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <asm/se7206.h>
 
 #define INTSTS0 0x31800000
 #define INTMSK1 0x31800006
 #define INTSEL  0x31800008
 
+#define IRQ0_IRQ 64
+#define IRQ1_IRQ 65
+#define IRQ3_IRQ 67
+
+#define INTC_IPR01 0xfffe0818
+#define INTC_ICR1  0xfffe0802
+
 static void disable_se7206_irq(unsigned int irq)
 {
        unsigned short val;
@@ -39,7 +47,7 @@ static void disable_se7206_irq(unsigned int irq)
        case IRQ1_IRQ:
                msk0 |= 0x000f;
                break;
-       case IRQ2_IRQ:
+       case IRQ3_IRQ:
                msk0 |= 0x0f00;
                msk1 |= 0x00ff;
                break;
@@ -70,7 +78,7 @@ static void enable_se7206_irq(unsigned int irq)
        case IRQ1_IRQ:
                msk0 &= ~0x000f;
                break;
-       case IRQ2_IRQ:
+       case IRQ3_IRQ:
                msk0 &= ~0x0f00;
                msk1 &= ~0x00ff;
                break;
@@ -96,7 +104,7 @@ static void eoi_se7206_irq(unsigned int irq)
        case IRQ1_IRQ:
                sts0 &= ~0x000f;
                break;
-       case IRQ2_IRQ:
+       case IRQ3_IRQ:
                sts0 &= ~0x0f00;
                sts1 &= ~0x00ff;
                break;
@@ -106,7 +114,7 @@ static void eoi_se7206_irq(unsigned int irq)
 }
 
 static struct irq_chip se7206_irq_chip __read_mostly = {
-       .name           = "SE7206-FPGA-IRQ",
+       .name           = "SE7206-FPGA",
        .mask           = disable_se7206_irq,
        .unmask         = enable_se7206_irq,
        .mask_ack       = disable_se7206_irq,
index 3666eca8a6581a0a46e59f52c4cbb742cb084320..d21775c28cda657199a5e8b96cb7117fa360d912 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7619 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o
+obj-y   := setup.o
diff --git a/arch/sh/boards/se/7619/io.c b/arch/sh/boards/se/7619/io.c
deleted file mode 100644 (file)
index 176f1f3..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *
- * linux/arch/sh/boards/se/7619/io.c
- *
- * Copyright (C) 2006  Yoshinori Sato
- *
- * I/O routine for Hitachi 7619 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <asm/se7619.h>
-#include <asm/irq.h>
-
-/* FIXME: M3A-ZAB7 Compact Flash Slot support */
-
-static inline void delay(void)
-{
-       ctrl_inw(0xa0000000);   /* Uncached ROM area (P2) */
-}
-
-#define badio(name,port) \
-  printk("bad I/O operation (%s) for port 0x%lx at 0x%08x\n", \
-        #name, (port), (__u32) __builtin_return_address(0))
-
-unsigned char se7619___inb(unsigned long port)
-{
-       badio(inb, port);
-       return 0;
-}
-
-unsigned char se7619___inb_p(unsigned long port)
-{
-       badio(inb_p, port);
-       delay();
-       return 0;
-}
-
-unsigned short se7619___inw(unsigned long port)
-{
-       badio(inw, port);
-       return 0;
-}
-
-unsigned int se7619___inl(unsigned long port)
-{
-       badio(inl, port);
-       return 0;
-}
-
-void se7619___outb(unsigned char value, unsigned long port)
-{
-       badio(outb, port);
-}
-
-void se7619___outb_p(unsigned char value, unsigned long port)
-{
-       badio(outb_p, port);
-       delay();
-}
-
-void se7619___outw(unsigned short value, unsigned long port)
-{
-       badio(outw, port);
-}
-
-void se7619___outl(unsigned int value, unsigned long port)
-{
-       badio(outl, port);
-}
-
-void se7619___insb(unsigned long port, void *addr, unsigned long count)
-{
-       badio(inw, port);
-}
-
-void se7619___insw(unsigned long port, void *addr, unsigned long count)
-{
-       badio(inw, port);
-}
-
-void se7619___insl(unsigned long port, void *addr, unsigned long count)
-{
-       badio(insl, port);
-}
-
-void se7619___outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       badio(insl, port);
-}
-
-void se7619___outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       badio(insl, port);
-}
-
-void se7619___outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       badio(outsw, port);
-}
index e627b26de0d00d97a6a81dd644addd28d4754a5f..52d2c4d5d2fa98327b306a62f7a39f0867dc2330 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <asm/io.h>
-#include <asm/se7619.h>
 #include <asm/machvec.h>
 
 /*
 struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_nr_irqs             = 108,
-       .mv_inb                 = se7619___inb,
-       .mv_inw                 = se7619___inw,
-       .mv_inl                 = se7619___inl,
-       .mv_outb                = se7619___outb,
-       .mv_outw                = se7619___outw,
-       .mv_outl                = se7619___outl,
-
-       .mv_inb_p               = se7619___inb_p,
-       .mv_inw_p               = se7619___inw,
-       .mv_inl_p               = se7619___inl,
-       .mv_outb_p              = se7619___outb_p,
-       .mv_outw_p              = se7619___outw,
-       .mv_outl_p              = se7619___outl,
-
-       .mv_insb                = se7619___insb,
-       .mv_insw                = se7619___insw,
-       .mv_insl                = se7619___insl,
-       .mv_outsb               = se7619___outsb,
-       .mv_outsw               = se7619___outsw,
-       .mv_outsl               = se7619___outsl,
 };
 ALIAS_MV(se)
index 60797b31089ce79dbd4fbe68a37df2bd735a266a..11dc272c618ef0f559fd12568a893047179f0cf1 100644 (file)
@@ -8,13 +8,49 @@
 # Copyright (C) 1999 Stuart Menefy
 #
 
-targets := zImage
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
+#
+# Assign safe dummy values if these variables are not defined,
+# in order to suppress error message.
+#
+CONFIG_PAGE_OFFSET     ?= 0x80000000
+CONFIG_MEMORY_START    ?= 0x0c000000
+CONFIG_BOOT_LINK_OFFSET        ?= 0x00800000
+CONFIG_ZERO_PAGE_OFFSET        ?= 0x00001000
+
+export CONFIG_PAGE_OFFSET CONFIG_MEMORY_START CONFIG_BOOT_LINK_OFFSET \
+       CONFIG_ZERO_PAGE_OFFSET
+
+targets := zImage vmlinux.srec uImage uImage.srec
 subdir- := compressed
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)
-       @echo 'Kernel: $@ is ready'
+       @echo '  Kernel: $@ is ready'
 
 $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
+KERNEL_LOAD    := $(shell printf "0x%8x" $$[$(CONFIG_PAGE_OFFSET)  + \
+                                            $(CONFIG_MEMORY_START) + \
+                                            $(CONFIG_ZERO_PAGE_OFFSET)+0x1000])
+
+quiet_cmd_uimage = UIMAGE  $@
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sh -O linux -T kernel \
+                  -C gzip -a $(KERNEL_LOAD) -e $(KERNEL_LOAD) \
+                  -n 'Linux-$(KERNELRELEASE)' -d $< $@
+
+$(obj)/uImage: $(obj)/zImage FORCE
+       $(call if_changed,uimage)
+       @echo '  Image $@ is ready'
+
+OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
+$(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
+       $(call if_changed,objcopy)
+
+OBJCOPYFLAGS_uImage.srec := -I binary -O srec
+$(obj)/uImage.srec: $(obj)/uImage
+       $(call if_changed,objcopy)
+
+clean-files    += uImage uImage.srec vmlinux.srec
index e5f4437900794a66874de91e62a557572f5b0e81..d9512416f88500847acff0eae59a90a8c3a092e1 100644 (file)
@@ -15,13 +15,7 @@ endif
 
 #
 # IMAGE_OFFSET is the load offset of the compression loader
-# Assign dummy values if these 2 variables are not defined,
-# in order to suppress error message.
 #
-CONFIG_PAGE_OFFSET     ?= 0x80000000
-CONFIG_MEMORY_START     ?= 0x0c000000
-CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
-
 IMAGE_OFFSET   := $(shell printf "0x%08x" $$[$(CONFIG_PAGE_OFFSET)  + \
                                              $(CONFIG_MEMORY_START) + \
                                              $(CONFIG_BOOT_LINK_OFFSET)])
index 4c26a192277d5b4135a68fc542a4c1499b9669a7..a8399b013729faa4bc10081518018ee86f1d813d 100644 (file)
@@ -8,6 +8,7 @@
 .text
 
 #include <linux/linkage.h>
+#include <asm/page.h>
 
        .global startup
 startup:
@@ -97,7 +98,7 @@ init_stack_addr:
 decompress_kernel_addr:
        .long   decompress_kernel
 kernel_start_addr:
-       .long   _text+0x1000
+       .long   _text+PAGE_SIZE
 
        .align  9
 fake_headers_as_bzImage:
index 35452d85b7f7f21ccf341ae3af407ed679dfb450..df65e305acf78b14710efa0ddc32998207fc9fbb 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/addrspace.h>
+#include <asm/page.h>
 #ifdef CONFIG_SH_STANDARD_BIOS
 #include <asm/sh_bios.h>
 #endif
@@ -229,7 +230,7 @@ long* stack_start = &user_stack[STACK_SIZE];
 void decompress_kernel(void)
 {
        output_data = 0;
-       output_ptr = P2SEGADDR((unsigned long)&_text+0x1000);
+       output_ptr = P2SEGADDR((unsigned long)&_text+PAGE_SIZE);
        free_mem_ptr = (unsigned long)&_end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
 
index 238c0f109907533b8e6ccfef7b124048aeddac4e..e7f8ddb0ada436bf693191b4bc7349caea54d954 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct  3 11:14:13 2006
+# Linux kernel version: 2.6.19
+# Thu Dec  7 17:13:04 2006
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -10,6 +10,9 @@ CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -33,6 +36,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -114,6 +118,8 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_SH_LANDISK=y
 # CONFIG_SH_TITAN is not set
 # CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
 # CONFIG_SH_UNKNOWN is not set
 
 #
@@ -125,6 +131,12 @@ CONFIG_CPU_SH4=y
 # SH-2 Processor Support
 #
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
 
 #
 # SH-3 Processor Support
@@ -160,6 +172,7 @@ CONFIG_CPU_SUBTYPE_SH7751R=y
 #
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
 
 #
 # SH4AL-DSP Processor Support
@@ -175,6 +188,9 @@ CONFIG_PAGE_OFFSET=0x80000000
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x04000000
 CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -196,16 +212,21 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # Processor features
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
 
 #
 # Timer support
 #
 CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
 CONFIG_SH_PCLK_FREQ=33333333
 
 #
@@ -216,9 +237,7 @@ CONFIG_SH_PCLK_FREQ=33333333
 #
 # DMA support
 #
-CONFIG_SH_DMA=y
-CONFIG_NR_ONCHIP_DMA_CHANNELS=4
-# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+# CONFIG_SH_DMA is not set
 
 #
 # Companion Chips
@@ -226,6 +245,11 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=4
 # CONFIG_HD6446X_SERIES is not set
 CONFIG_HEARTBEAT=y
 
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
 #
 # Kernel features
 #
@@ -340,11 +364,13 @@ CONFIG_IP_PNP=y
 # 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_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
 
 #
 # IP: Virtual Server Configuration
@@ -361,24 +387,12 @@ CONFIG_NETFILTER=y
 # Core Netfilter Configuration
 #
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
 # CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_CT_ACCT=y
-CONFIG_IP_NF_CONNTRACK_MARK=y
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-CONFIG_IP_NF_AMANDA=m
-# CONFIG_IP_NF_PPTP is not set
-# CONFIG_IP_NF_H323 is not set
-# CONFIG_IP_NF_SIP is not set
 CONFIG_IP_NF_QUEUE=m
 
 #
@@ -476,6 +490,12 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
 #
 # ATA/ATAPI/MFM/RLL support
 #
@@ -519,6 +539,7 @@ CONFIG_BLK_DEV_AEC62XX=y
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X 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_IT821X is not set
@@ -542,6 +563,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
@@ -561,6 +583,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
 
 #
 # SCSI Transports
@@ -602,12 +625,12 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_STEX is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS 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_SYM53C416 is not set
 # CONFIG_SCSI_DC395x is not set
@@ -615,6 +638,7 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
 
 #
 # PCMCIA SCSI adapter support
@@ -757,6 +781,7 @@ CONFIG_8139CP=y
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
 
 #
 # Token Ring devices
@@ -871,10 +896,6 @@ CONFIG_HW_RANDOM=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 # CONFIG_DRM is not set
 
 #
@@ -889,7 +910,6 @@ CONFIG_HW_RANDOM=y
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -905,6 +925,7 @@ CONFIG_HW_RANDOM=y
 #
 # Dallas's 1-wire bus
 #
+# CONFIG_W1 is not set
 
 #
 # Hardware Monitoring support
@@ -916,10 +937,6 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
-#
-# Misc devices
-#
-
 #
 # Multimedia devices
 #
@@ -1037,6 +1054,7 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1106,7 +1124,6 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
 
 #
 # USB Imaging devices
@@ -1121,6 +1138,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_KAWETH is not set
 CONFIG_USB_PEGASUS=m
 CONFIG_USB_RTL8150=m
+# CONFIG_USB_USBNET_MII is not set
 # CONFIG_USB_USBNET is not set
 CONFIG_USB_MON=y
 
@@ -1156,6 +1174,7 @@ CONFIG_USB_SERIAL_FTDI_SIO=m
 # CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
 # CONFIG_USB_SERIAL_MOS7840 is not set
 # CONFIG_USB_SERIAL_NAVMAN is not set
 CONFIG_USB_SERIAL_PL2303=m
@@ -1167,6 +1186,7 @@ CONFIG_USB_SERIAL_PL2303=m
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OPTION is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
 
 #
 # USB Miscellaneous drivers
@@ -1188,6 +1208,7 @@ CONFIG_USB_EMI26=m
 CONFIG_USB_SISUSBVGA=m
 CONFIG_USB_SISUSBVGA_CON=y
 # CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -1254,6 +1275,7 @@ 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_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -1264,6 +1286,7 @@ CONFIG_REISERFS_FS=y
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
@@ -1414,6 +1437,7 @@ CONFIG_NLS_CODEPAGE_932=y
 #
 # Kernel hacking
 #
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
 CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_MAGIC_SYSRQ is not set
@@ -1422,6 +1446,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_EARLY_SCIF_CONSOLE is not set
 # CONFIG_EARLY_PRINTK is not set
@@ -1445,6 +1470,4 @@ CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
 CONFIG_PLIST=y
index 36cec0b6e7c1ae102c41d8c97a9377547b6c481f..87ab9080fd1db3b5a4a26cdca8e686e4e6c20709 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc4
-# Sun Nov  5 16:20:10 2006
+# Linux kernel version: 2.6.19
+# Wed Dec  6 14:40:15 2006
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -11,6 +11,8 @@ CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 # CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -34,24 +36,23 @@ CONFIG_LOCALVERSION=""
 # CONFIG_IKCONFIG is not set
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
-CONFIG_UID16=y
+# CONFIG_UID16 is not set
 # CONFIG_SYSCTL_SYSCALL is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_TINY_SHMEM=y
-CONFIG_BASE_SMALL=0
+CONFIG_BASE_SMALL=1
 # CONFIG_SLOB is not set
 
 #
@@ -160,6 +161,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 #
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
 
 #
 # SH4AL-DSP Processor Support
@@ -172,7 +174,10 @@ CONFIG_CPU_SUBTYPE_SH7206=y
 #
 CONFIG_PAGE_OFFSET=0x00000000
 CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -194,6 +199,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 # Processor features
 #
 # CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_BIG_ENDIAN=y
 # CONFIG_SH_FPU is not set
 # CONFIG_SH_FPU_EMU is not set
 # CONFIG_SH_DSP is not set
@@ -203,6 +209,8 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 #
 CONFIG_SH_CMT=y
 # CONFIG_SH_MTU2 is not set
+CONFIG_SH_TIMER_IRQ=140
+# CONFIG_NO_IDLE_HZ is not set
 CONFIG_SH_PCLK_FREQ=33333333
 CONFIG_SH_CLK_MD=6
 
@@ -221,6 +229,11 @@ CONFIG_SH_CLK_MD=6
 #
 # CONFIG_HD6446X_SERIES is not set
 
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
 #
 # Kernel features
 #
@@ -279,9 +292,6 @@ CONFIG_NET=y
 # CONFIG_NETDEBUG is not set
 # CONFIG_PACKET is not set
 # CONFIG_UNIX is not set
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -297,9 +307,9 @@ CONFIG_IP_FIB_HASH=y
 # 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_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
@@ -371,7 +381,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
@@ -422,7 +432,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x1000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
 CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 # CONFIG_MTD_SOLUTIONENGINE is not set
 # CONFIG_MTD_UCLINUX is not set
@@ -468,10 +478,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 # 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_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -519,7 +526,50 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # Network device support
 #
-# CONFIG_NETDEVICES is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 
@@ -536,7 +586,26 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -564,8 +633,7 @@ CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_UNIX98_PTYS is not set
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
 
 #
 # IPMI
@@ -576,7 +644,7 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM is not set
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -610,12 +678,8 @@ CONFIG_HW_RANDOM=y
 #
 # Hardware Monitoring support
 #
-CONFIG_HWMON=y
+# CONFIG_HWMON is not set
 # CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Multimedia devices
@@ -630,7 +694,7 @@ CONFIG_HWMON=y
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB is not set
 
 #
@@ -701,8 +765,7 @@ CONFIG_FIRMWARE_EDID=y
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_EXT4DEV_FS is not set
 # CONFIG_REISERFS_FS is not set
@@ -755,7 +818,7 @@ CONFIG_RAMFS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
-CONFIG_CRAMFS=y
+# CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -793,8 +856,9 @@ CONFIG_MSDOS_PARTITION=y
 #
 # Kernel hacking
 #
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_MUST_CHECK is not set
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_KERNEL is not set
@@ -819,7 +883,7 @@ CONFIG_LOG_BUF_SHIFT=14
 #
 # Library routines
 #
-CONFIG_CRC_CCITT=y
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se7619_defconfig b/arch/sh/configs/se7619_defconfig
new file mode 100644 (file)
index 0000000..20ac7f4
--- /dev/null
@@ -0,0 +1,744 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19
+# Wed Dec  6 16:35:36 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_SLAB=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+CONFIG_SH_7619_SOLUTION_ENGINE=y
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+CONFIG_CPU_SUBTYPE_SH7619=y
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_PAGE_OFFSET=0x00000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+CONFIG_SH_WRITETHROUGH=y
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+# CONFIG_SH_DSP is not set
+
+#
+# Timer support
+#
+CONFIG_SH_CMT=y
+CONFIG_SH_TIMER_IRQ=86
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=31250000
+CONFIG_SH_CLK_MD=5
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+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 is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=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
+
+#
+# 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
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xa0000000
+CONFIG_MTD_PHYSMAP_LEN=0x01000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_SOLUTIONENGINE is not set
+# CONFIG_MTD_UCLINUX is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# 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
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV 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_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY 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_SYSCTL=y
+# CONFIG_SYSFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# 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_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
index f2b9157c314fb15e073e20c25b8202c317def8b8..b3d20c0e021fee71a00620fb767c120697911e17 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/push-switch.h>
 
 #define DRV_NAME "push-switch"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.1"
 
 static ssize_t switch_show(struct device *dev,
                           struct device_attribute *attr,
@@ -32,10 +32,10 @@ static void switch_timer(unsigned long data)
        schedule_work(&psw->work);
 }
 
-static void switch_work_handler(void *data)
+static void switch_work_handler(struct work_struct *work)
 {
-       struct platform_device *pdev = data;
-       struct push_switch *psw = platform_get_drvdata(pdev);
+       struct push_switch *psw = container_of(work, struct push_switch, work);
+       struct platform_device *pdev = psw->pdev;
 
        psw->state = 0;
 
@@ -76,12 +76,15 @@ static int switch_drv_probe(struct platform_device *pdev)
                }
        }
 
-       INIT_WORK(&psw->work, switch_work_handler, pdev);
+       INIT_WORK(&psw->work, switch_work_handler);
        init_timer(&psw->debounce);
 
        psw->debounce.function = switch_timer;
        psw->debounce.data = (unsigned long)psw;
 
+       /* Workqueue API brain-damage */
+       psw->pdev = pdev;
+
        platform_set_drvdata(pdev, psw);
 
        return 0;
index 0582e6712b7927aaf6bf3841758e7ba39f5f0329..d055a3ea6b4b3ebab9551053246a3dfc88b9bc3d 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_CPU_SH2)           = sh2/
 obj-$(CONFIG_CPU_SH2A)         = sh2a/
 obj-$(CONFIG_CPU_SH3)          = sh3/
 obj-$(CONFIG_CPU_SH4)          = sh4/
+obj-$(CONFIG_CPU_SH4A)         += sh4a/
 
 obj-$(CONFIG_UBC_WAKEUP)       += ubc.o
 obj-$(CONFIG_SH_ADC)           += adc.o
index 34d51b3745eac80e35fccbb804f571b991595013..d51fa5e9904a8b92d3b5254720de5288fd0e77d5 100644 (file)
@@ -177,15 +177,21 @@ interrupt_entry:
 7:     .long   do_IRQ
 8:     .long   do_exception_error
        
-trap_entry:    
-       add     #-0x10,r9
+trap_entry:
+       /* verbose BUG trapa entry check */
+       mov     #0x3e,r8
+       cmp/ge  r8,r9
+       bf/s    1f
+        add    #-0x10,r9
+       add     #0x10,r9
+1:     
        shll2   r9                      ! TRA
        mov     #OFF_TRA,r8
        add     r15,r8
        mov.l   r9,@r8
        mov     r9,r8
 #ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   5f, r9
+       mov.l   2f, r9
        jsr     @r9
         nop
 #endif
@@ -194,12 +200,8 @@ trap_entry:
         nop
        
        .align  2
-1:     .long   syscall_exit
-2:     .long   break_point_trap_software
-3:     .long   NR_syscalls
-4:     .long   sys_call_table
 #ifdef CONFIG_TRACE_IRQFLAGS
-5:     .long   trace_hardirqs_on
+2:     .long   trace_hardirqs_on
 #endif
 
 #if defined(CONFIG_SH_STANDARD_BIOS)
@@ -264,7 +266,7 @@ ENTRY(address_error_handler)
 restore_all:
        cli
 #ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   3f, r0
+       mov.l   1f, r0
        jsr     @r0
         nop
 #endif
@@ -309,20 +311,14 @@ restore_all:
        mov.l   @r15,r15
        rte
         nop
-2:
-       mov.l   1f,r8
-       mov.l   2f,r9
-       jmp     @r9
-        lds    r8,pr
 
-       .align  2
+#ifdef CONFIG_TRACE_IRQFLAGS
+1:     .long   trace_hardirqs_off
+#endif
 $current_thread_info:
        .long   __current_thread_info
 $cpu_mode:     
        .long   __cpu_mode
-#ifdef CONFIG_TRACE_IRQFLAGS
-3:     .long   trace_hardirqs_off
-#endif
                
 ! common exception handler
 #include "../../entry-common.S"
index 82c2d905152f14525b01386cb4c4c6958ba7c929..79283e6c1d8f069a87efb9241e6dee36ca23c94c 100644 (file)
@@ -51,3 +51,44 @@ static int __init sh7619_devices_setup(void)
                                    ARRAY_SIZE(sh7619_devices));
 }
 __initcall(sh7619_devices_setup);
+
+#define INTC_IPRC      0xf8080000UL
+#define INTC_IPRD      0xf8080002UL
+
+#define CMI0_IRQ       86
+
+#define SCIF0_ERI_IRQ  88
+#define SCIF0_RXI_IRQ  89
+#define SCIF0_BRI_IRQ  90
+#define SCIF0_TXI_IRQ  91
+
+#define SCIF1_ERI_IRQ  92
+#define SCIF1_RXI_IRQ  93
+#define SCIF1_BRI_IRQ  94
+#define SCIF1_TXI_IRQ  95
+
+#define SCIF2_BRI_IRQ  96
+#define SCIF2_ERI_IRQ  97
+#define SCIF2_RXI_IRQ  98
+#define SCIF2_TXI_IRQ  99
+
+static struct ipr_data sh7619_ipr_map[] = {
+       { CMI0_IRQ,      INTC_IPRC, 1, 2 },
+       { SCIF0_ERI_IRQ, INTC_IPRD, 3, 3 },
+       { SCIF0_RXI_IRQ, INTC_IPRD, 3, 3 },
+       { SCIF0_BRI_IRQ, INTC_IPRD, 3, 3 },
+       { SCIF0_TXI_IRQ, INTC_IPRD, 3, 3 },
+       { SCIF1_ERI_IRQ, INTC_IPRD, 2, 3 },
+       { SCIF1_RXI_IRQ, INTC_IPRD, 2, 3 },
+       { SCIF1_BRI_IRQ, INTC_IPRD, 2, 3 },
+       { SCIF1_TXI_IRQ, INTC_IPRD, 2, 3 },
+       { SCIF2_ERI_IRQ, INTC_IPRD, 1, 3 },
+       { SCIF2_RXI_IRQ, INTC_IPRD, 1, 3 },
+       { SCIF2_BRI_IRQ, INTC_IPRD, 1, 3 },
+       { SCIF2_TXI_IRQ, INTC_IPRD, 1, 3 },
+};
+
+void __init init_IRQ_ipr(void)
+{
+       make_ipr_irq(sh7619_ipr_map, ARRAY_SIZE(sh7619_ipr_map));
+}
index cdfeef49e62ea811b2348a95836d7e7d878401a0..4b60fcc7d66755e9d7c9614adeaac9251df8a1f5 100644 (file)
@@ -17,22 +17,22 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xfffe8000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 240, 241, 242, 243},
+               .irqs           =  { 241, 242, 243, 240},
        }, {
                .mapbase        = 0xfffe8800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 244, 245, 246, 247},
+               .irqs           =  { 247, 244, 245, 246},
        }, {
                .mapbase        = 0xfffe9000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 248, 249, 250, 251},
+               .irqs           =  { 249, 250, 251, 248},
        }, {
                .mapbase        = 0xfffe9800,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           =  { 252, 253, 254, 255},
+               .irqs           =  { 253, 254, 255, 252},
        }, {
                .flags = 0,
        }
@@ -56,3 +56,57 @@ static int __init sh7206_devices_setup(void)
                                    ARRAY_SIZE(sh7206_devices));
 }
 __initcall(sh7206_devices_setup);
+
+#define INTC_IPR08     0xfffe0c04UL
+#define INTC_IPR09     0xfffe0c06UL
+#define INTC_IPR14     0xfffe0c10UL
+
+#define CMI0_IRQ       140
+
+#define MTU1_TGI1A     164
+
+#define SCIF0_BRI_IRQ  240
+#define SCIF0_ERI_IRQ  241
+#define SCIF0_RXI_IRQ  242
+#define SCIF0_TXI_IRQ  243
+
+#define SCIF1_BRI_IRQ  244
+#define SCIF1_ERI_IRQ  245
+#define SCIF1_RXI_IRQ  246
+#define SCIF1_TXI_IRQ  247
+
+#define SCIF2_BRI_IRQ  248
+#define SCIF2_ERI_IRQ  249
+#define SCIF2_RXI_IRQ  250
+#define SCIF2_TXI_IRQ  251
+
+#define SCIF3_BRI_IRQ  252
+#define SCIF3_ERI_IRQ  253
+#define SCIF3_RXI_IRQ  254
+#define SCIF3_TXI_IRQ  255
+
+static struct ipr_data sh7206_ipr_map[] = {
+       { CMI0_IRQ,      INTC_IPR08, 3, 2 },
+       { MTU2_TGI1A,    INTC_IPR09, 1, 2 },
+       { SCIF0_ERI_IRQ, INTC_IPR14, 3, 3 },
+       { SCIF0_RXI_IRQ, INTC_IPR14, 3, 3 },
+       { SCIF0_BRI_IRQ, INTC_IPR14, 3, 3 },
+       { SCIF0_TXI_IRQ, INTC_IPR14, 3, 3 },
+       { SCIF1_ERI_IRQ, INTC_IPR14, 2, 3 },
+       { SCIF1_RXI_IRQ, INTC_IPR14, 2, 3 },
+       { SCIF1_BRI_IRQ, INTC_IPR14, 2, 3 },
+       { SCIF1_TXI_IRQ, INTC_IPR14, 2, 3 },
+       { SCIF2_ERI_IRQ, INTC_IPR14, 1, 3 },
+       { SCIF2_RXI_IRQ, INTC_IPR14, 1, 3 },
+       { SCIF2_BRI_IRQ, INTC_IPR14, 1, 3 },
+       { SCIF2_TXI_IRQ, INTC_IPR14, 1, 3 },
+       { SCIF3_ERI_IRQ, INTC_IPR14, 0, 3 },
+       { SCIF3_RXI_IRQ, INTC_IPR14, 0, 3 },
+       { SCIF3_BRI_IRQ, INTC_IPR14, 0, 3 },
+       { SCIF3_TXI_IRQ, INTC_IPR14, 0, 3 },
+};
+
+void __init init_IRQ_ipr(void)
+{
+       make_ipr_irq(sh7206_ipr_map, ARRAY_SIZE(sh7206_ipr_map));
+}
index 6e415baf04b4f23bfb5767172dfbe18485ec1b2e..19ca68c71884176ed9f7f2230ab4618660842a47 100644 (file)
@@ -12,17 +12,12 @@ obj-$(CONFIG_SH_STORE_QUEUES)               += sq.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7750)       += setup-sh7750.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)       += setup-sh7750.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7760)       += setup-sh7760.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7770)       += setup-sh7770.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += setup-sh7780.o
-obj-$(CONFIG_CPU_SUBTYPE_SH73180)      += setup-sh73180.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH4_202)      += setup-sh4-202.o
 
 # Primary on-chip clocks (common)
+ifndef CONFIG_CPU_SH4A
 clock-$(CONFIG_CPU_SH4)                        := clock-sh4.o
-clock-$(CONFIG_CPU_SUBTYPE_SH73180)    := clock-sh73180.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7770)     := clock-sh7770.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7780)     := clock-sh7780.o
+endif
 
 # Additional clocks by subtype
 clock-$(CONFIG_CPU_SUBTYPE_SH4_202)    += clock-sh4-202.o
index afe0f1b1c030636f6cd156c8d48796d5843e0cb4..9031a22a2ce7878b03378c48c353b39866fbce5b 100644 (file)
@@ -119,11 +119,20 @@ int __init detect_cpu_and_cache_system(void)
                break;
        case 0x3000:
        case 0x3003:
+       case 0x3009:
                cpu_data->type = CPU_SH7343;
                cpu_data->icache.ways = 4;
                cpu_data->dcache.ways = 4;
                cpu_data->flags |= CPU_HAS_LLSC;
                break;
+       case 0x3008:
+               if (prr == 0xa0) {
+                       cpu_data->type = CPU_SH7722;
+                       cpu_data->icache.ways = 4;
+                       cpu_data->dcache.ways = 4;
+                       cpu_data->flags |= CPU_HAS_LLSC;
+               }
+               break;
        case 0x8000:
                cpu_data->type = CPU_ST40RA;
                cpu_data->flags |= CPU_HAS_FPU;
index bbcb06f18b04dc6d8f697873d62880bdbeb52481..cbac27634c0b23441409c7835dcb9a914bf2706c 100644 (file)
 #include <linux/io.h>
 #include <asm/sci.h>
 
+static struct resource rtc_resources[] = {
+       [0] = {
+               .start  = 0xffc80000,
+               .end    = 0xffc80000 + 0x58 - 1,
+               .flags  = IORESOURCE_IO,
+       },
+       [1] = {
+               /* Period IRQ */
+               .start  = 21,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* Carry IRQ */
+               .start  = 22,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               /* Alarm IRQ */
+               .start  = 20,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device rtc_device = {
+       .name           = "sh-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rtc_resources),
+       .resource       = rtc_resources,
+};
+
 static struct plat_sci_port sci_platform_data[] = {
        {
                .mapbase        = 0xffe00000,
@@ -39,6 +69,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7750_devices[] __initdata = {
+       &rtc_device,
        &sci_device,
 };
 
index 0c9ea38d2caa0268a53179b75aec501bac0c443e..d7fff752e569964652915e44a2197abe7eb85b5d 100644 (file)
@@ -111,8 +111,9 @@ static int __sq_remap(struct sq_mapping *map, unsigned long flags)
 
        vma->phys_addr = map->addr;
 
-       if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
-                            map->size, flags)) {
+       if (ioremap_page_range((unsigned long)vma->addr,
+                              (unsigned long)vma->addr + map->size,
+                              vma->phys_addr, __pgprot(flags))) {
                vunmap(vma->addr);
                return -EAGAIN;
        }
@@ -176,7 +177,7 @@ unsigned long sq_remap(unsigned long phys, unsigned int size,
 
        map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
 
-       ret = __sq_remap(map, flags);
+       ret = __sq_remap(map, pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
        if (unlikely(ret != 0))
                goto out;
 
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
new file mode 100644 (file)
index 0000000..a8f493f
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for the Linux/SuperH SH-4 backends.
+#
+
+# CPU subtype setup
+obj-$(CONFIG_CPU_SUBTYPE_SH7770)       += setup-sh7770.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH73180)      += setup-sh73180.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
+
+# Primary on-chip clocks (common)
+clock-$(CONFIG_CPU_SUBTYPE_SH73180)    := clock-sh73180.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7770)     := clock-sh7770.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7780)     := clock-sh7780.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7343.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7343.o
+
+obj-y  += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
new file mode 100644 (file)
index 0000000..1707a21
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * arch/sh/kernel/cpu/sh4/clock-sh7343.c
+ *
+ * SH7343/SH7722 support for the clock framework
+ *
+ *  Copyright (C) 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+/*
+ * SH7343/SH7722 uses a common set of multipliers and divisors, so this
+ * is quite simple..
+ */
+static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+
+#define pll_calc() (((ctrl_inl(FRQCR) >> 24) & 0x1f) + 1)
+
+static void master_clk_init(struct clk *clk)
+{
+       clk->parent = clk_get(NULL, "cpu_clk");
+}
+
+static void master_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inl(FRQCR) & 0x000f);
+       clk->rate *= clk->parent->rate * multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_master_clk_ops = {
+       .init           = master_clk_init,
+       .recalc         = master_clk_recalc,
+};
+
+static void module_clk_init(struct clk *clk)
+{
+       clk->parent = NULL;
+       clk->rate = CONFIG_SH_PCLK_FREQ;
+}
+
+static struct clk_ops sh7343_module_clk_ops = {
+       .init           = module_clk_init,
+};
+
+static void bus_clk_init(struct clk *clk)
+{
+       clk->parent = clk_get(NULL, "cpu_clk");
+}
+
+static void bus_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inl(FRQCR) >> 8) & 0x000f;
+       clk->rate = clk->parent->rate * multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_bus_clk_ops = {
+       .init           = bus_clk_init,
+       .recalc         = bus_clk_recalc,
+};
+
+static void cpu_clk_init(struct clk *clk)
+{
+       clk->parent = clk_get(NULL, "module_clk");
+       clk->flags |= CLK_RATE_PROPAGATES;
+       clk_set_rate(clk, clk_get_rate(clk));
+}
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inl(FRQCR) >> 20) & 0x000f;
+       clk->rate = clk->parent->rate * pll_calc() *
+               multipliers[idx] / divisors[idx];
+}
+
+static struct clk_ops sh7343_cpu_clk_ops = {
+       .init           = cpu_clk_init,
+       .recalc         = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7343_clk_ops[] = {
+       &sh7343_master_clk_ops,
+       &sh7343_module_clk_ops,
+       &sh7343_bus_clk_ops,
+       &sh7343_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+       if (idx < ARRAY_SIZE(sh7343_clk_ops))
+               *ops = sh7343_clk_ops[idx];
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
new file mode 100644 (file)
index 0000000..1143fbf
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * SH7722 Setup
+ *
+ *  Copyright (C) 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+       {
+               .mapbase        = 0xffe00000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 80, 81, 83, 82 },
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct platform_device *sh7722_devices[] __initdata = {
+       &sci_device,
+};
+
+static int __init sh7722_devices_setup(void)
+{
+       return platform_add_devices(sh7722_devices,
+                                   ARRAY_SIZE(sh7722_devices));
+}
+__initcall(sh7722_devices_setup);
+
+static struct ipr_data sh7722_ipr_map[] = {
+       /* IRQ, IPR-idx, shift, prio */
+       { 16, 0, 12, 2 }, /* TMU0 */
+       { 17, 0,  8, 2 }, /* TMU1 */
+       { 80, 6, 12, 3 }, /* SCIF ERI */
+       { 81, 6, 12, 3 }, /* SCIF RXI */
+       { 82, 6, 12, 3 }, /* SCIF BRI */
+       { 83, 6, 12, 3 }, /* SCIF TXI */
+};
+
+static unsigned long ipr_offsets[] = {
+       0xa4080000, /*  0: IPRA */
+       0xa4080004, /*  1: IPRB */
+       0xa4080008, /*  2: IPRC */
+       0xa408000c, /*  3: IPRD */
+       0xa4080010, /*  4: IPRE */
+       0xa4080014, /*  5: IPRF */
+       0xa4080018, /*  6: IPRG */
+       0xa408001c, /*  7: IPRH */
+       0xa4080020, /*  8: IPRI */
+       0xa4080024, /*  9: IPRJ */
+       0xa4080028, /* 10: IPRK */
+       0xa408002c, /* 11: IPRL */
+};
+
+unsigned int map_ipridx_to_addr(int idx)
+{
+       if (unlikely(idx >= ARRAY_SIZE(ipr_offsets)))
+               return 0;
+       return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr(void)
+{
+       make_ipr_irq(sh7722_ipr_map, ARRAY_SIZE(sh7722_ipr_map));
+}
index 60340823798ab99f19d13ab31af5e3eb1ff45369..560b91cdd15ced07aef986db027f9b3ad6daf1fa 100644 (file)
@@ -144,16 +144,16 @@ static struct console *early_console =
        ;
 
 static int __initdata keep_early;
+static int early_console_initialized;
 
-int __init setup_early_printk(char *opt)
+int __init setup_early_printk(char *buf)
 {
-       char *space;
-       char buf[256];
+       if (!buf)
+               return 0;
 
-       strlcpy(buf, opt, sizeof(buf));
-       space = strchr(buf, ' ');
-       if (space)
-               *space = 0;
+       if (early_console_initialized)
+               return 0;
+       early_console_initialized = 1;
 
        if (strstr(buf, "keep"))
                keep_early = 1;
@@ -175,12 +175,14 @@ int __init setup_early_printk(char *opt)
        if (likely(early_console))
                register_console(early_console);
 
-       return 1;
+       return 0;
 }
-__setup("earlyprintk=", setup_early_printk);
+early_param("earlyprintk", setup_early_printk);
 
 void __init disable_early_printk(void)
 {
+       if (!early_console_initialized || !early_console)
+               return;
        if (!keep_early) {
                printk("disabling early console\n");
                unregister_console(early_console);
index 29136a35d7c78823c69e8f031da22e6dc2e953b9..fc279aeb73ab946c83106be747659f1d2fb04e48 100644 (file)
@@ -79,18 +79,29 @@ debug_kernel_sw:
        .align  2
 3:     .long   kgdb_handle_exception
 #endif /* CONFIG_SH_KGDB */
-
+#ifdef CONFIG_SH_STANDARD_BIOS
+       bra     debug_kernel_fw
+        nop
+#endif
 #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
 
-
        .align  2
 debug_trap:    
 #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+       mov     r8, r0
+       shlr2   r0
+       cmp/eq  #0x3f, r0               ! sh_bios() trap
+       bf      1f
+#ifdef CONFIG_SH_KGDB
+       cmp/eq  #0xff, r0               ! XXX: KGDB trap, fix for SH-2.
+       bf      1f
+#endif
        mov     #OFF_SR, r0
        mov.l   @(r0,r15), r0           ! get status register
        shll    r0
        shll    r0                      ! kernel space?
        bt/s    debug_kernel
+1:
 #endif
         mov.l  @r15, r0                ! Restore R0 value
        mov.l   1f, r8
index 6aca4bc6ec5d55e5dd649edb36be0aa3702d7925..71a3ad7d283e2156cbbae33a2338738e2005b090 100644 (file)
@@ -33,7 +33,8 @@ ENTRY(empty_zero_page)
        .long   0x00360000      /* INITRD_START */
        .long   0x000a0000      /* INITRD_SIZE */
        .long   0
-       .balign PAGE_SIZE,0,PAGE_SIZE
+1:
+       .skip   PAGE_SIZE - empty_zero_page - 1b
 
        .text   
 /*
index f3e2631be14456033c845eb28f0760ef8a875cea..486c06e180333404baf796be54b796b110d7f448 100644 (file)
@@ -470,9 +470,10 @@ unsigned long get_wchan(struct task_struct *p)
         */
        pc = thread_saved_pc(p);
        if (in_sched_functions(pc)) {
-               schedule_frame = ((unsigned long *)(long)p->thread.sp)[1];
-               return (unsigned long)((unsigned long *)schedule_frame)[1];
+               schedule_frame = (unsigned long)p->thread.sp;
+               return ((unsigned long *)schedule_frame)[21];
        }
+
        return pc;
 }
 
@@ -498,6 +499,16 @@ asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5,
 {
        struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 
+       /* Rewind */
        regs->pc -= 2;
+
+#ifdef CONFIG_BUG
+       if (__kernel_text_address(instruction_pointer(regs))) {
+               u16 insn = *(u16 *)instruction_pointer(regs);
+               if (insn == TRAPA_BUG_OPCODE)
+                       handle_BUG(regs);
+       }
+#endif
+
        force_sig(SIGTRAP, current);
 }
index f8dd6b7bfab05439bc5623bb34ce22230669c06b..225f9ea5cdd7c8d0c7dadcf74664bde8576506d3 100644 (file)
@@ -84,8 +84,7 @@ unsigned long memory_start, memory_end;
 
 static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
                                  struct sh_machine_vector** mvp,
-                                 unsigned long *mv_io_base,
-                                 int *mv_mmio_enable)
+                                 unsigned long *mv_io_base)
 {
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
        int len = 0;
@@ -112,23 +111,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
                        }
                }
 
-#ifdef CONFIG_EARLY_PRINTK
-               if (c == ' ' && !memcmp(from, "earlyprintk=", 12)) {
-                       char *ep_end;
-
-                       if (to != command_line)
-                               to--;
-
-                       from += 12;
-                       ep_end = strchr(from, ' ');
-
-                       setup_early_printk(from);
-                       printk("early console enabled\n");
-
-                       from = ep_end;
-               }
-#endif
-
                if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
                        char* mv_end;
                        char* mv_comma;
@@ -145,7 +127,6 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
                                int ints[3];
                                get_options(mv_comma+1, ARRAY_SIZE(ints), ints);
                                *mv_io_base = ints[1];
-                               *mv_mmio_enable = ints[2];
                                mv_len = mv_comma - from;
                        } else {
                                mv_len = mv_end - from;
@@ -158,6 +139,7 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
 
                        *mvp = get_mv_byname(mv_name);
                }
+
                c = *(from++);
                if (!c)
                        break;
@@ -177,9 +159,8 @@ static int __init sh_mv_setup(char **cmdline_p)
        struct sh_machine_vector *mv = NULL;
        char mv_name[MV_NAME_SIZE] = "";
        unsigned long mv_io_base = 0;
-       int mv_mmio_enable = 0;
 
-       parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base, &mv_mmio_enable);
+       parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base);
 
 #ifdef CONFIG_SH_UNKNOWN
        if (mv == NULL) {
@@ -258,6 +239,7 @@ void __init setup_arch(char **cmdline_p)
 
        sh_mv_setup(cmdline_p);
 
+
        /*
         * Find the highest page frame number we have available
         */
@@ -305,6 +287,7 @@ void __init setup_arch(char **cmdline_p)
                                  PFN_PHYS(pages));
        }
 
+
        /*
         * Reserve the kernel text and
         * Reserve the bootmem bitmap. We do this in two steps (first step
@@ -325,14 +308,18 @@ void __init setup_arch(char **cmdline_p)
        ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
        if (&__rd_start != &__rd_end) {
                LOADER_TYPE = 1;
-               INITRD_START = PHYSADDR((unsigned long)&__rd_start) - __MEMORY_START;
-               INITRD_SIZE = (unsigned long)&__rd_end - (unsigned long)&__rd_start;
+               INITRD_START = PHYSADDR((unsigned long)&__rd_start) -
+                                       __MEMORY_START;
+               INITRD_SIZE = (unsigned long)&__rd_end -
+                             (unsigned long)&__rd_start;
        }
 
        if (LOADER_TYPE && INITRD_START) {
                if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
-                       reserve_bootmem_node(NODE_DATA(0), INITRD_START+__MEMORY_START, INITRD_SIZE);
-                       initrd_start = INITRD_START + PAGE_OFFSET + __MEMORY_START;
+                       reserve_bootmem_node(NODE_DATA(0), INITRD_START +
+                                               __MEMORY_START, INITRD_SIZE);
+                       initrd_start = INITRD_START + PAGE_OFFSET +
+                                       __MEMORY_START;
                        initrd_end = initrd_start + INITRD_SIZE;
                } else {
                        printk("initrd extends beyond end of memory "
@@ -404,7 +391,7 @@ static const char *cpu_name[] = {
        [CPU_SH4_202]   = "SH4-202",    [CPU_SH4_501]   = "SH4-501",
        [CPU_SH7770]    = "SH7770",     [CPU_SH7780]    = "SH7780",
        [CPU_SH7781]    = "SH7781",     [CPU_SH7343]    = "SH7343",
-       [CPU_SH7785]    = "SH7785",
+       [CPU_SH7785]    = "SH7785",     [CPU_SH7722]    = "SH7722",
        [CPU_SH_NONE]   = "Unknown"
 };
 
index ceee7914340121bb7ba33664b528869233bb123b..e6106239a0fec627120ee62c116fa830fb82322e 100644 (file)
@@ -70,13 +70,26 @@ DECLARE_EXPORT(__sdivsi3);
 DECLARE_EXPORT(__ashrdi3);
 DECLARE_EXPORT(__ashldi3);
 DECLARE_EXPORT(__lshrdi3);
-DECLARE_EXPORT(__movstr);
 DECLARE_EXPORT(__movstrSI16);
+#if __GNUC__ == 4
+DECLARE_EXPORT(__movmem);
+#else
+DECLARE_EXPORT(__movstr);
+#endif
 
 #ifdef CONFIG_CPU_SH4
+#if __GNUC__ == 4
+DECLARE_EXPORT(__movmem_i4_even);
+DECLARE_EXPORT(__movmem_i4_odd);
+DECLARE_EXPORT(__movmemSI12_i4);
+DECLARE_EXPORT(__sdivsi3_i4i);
+DECLARE_EXPORT(__udiv_qrnnd_16);
+DECLARE_EXPORT(__udivsi3_i4i);
+#else /* GCC 3.x */
 DECLARE_EXPORT(__movstr_i4_even);
 DECLARE_EXPORT(__movstr_i4_odd);
 DECLARE_EXPORT(__movstrSI12_i4);
+#endif /* __GNUC__ == 4 */
 #endif
 
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
index bb1c480a59c74f2713a39482e5d89fba8314e886..379c88bf5d9a0a8faeb50bd1ab39c6d524784e54 100644 (file)
@@ -101,7 +101,7 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
  */
 
 #define MOVW(n)         (0x9300|((n)-2))       /* Move mem word at PC+n to R3 */
-#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#if defined(CONFIG_CPU_SH2)
 #define TRAP_NOARG 0xc320              /* Syscall w/no args (NR in R3) */
 #else
 #define TRAP_NOARG 0xc310              /* Syscall w/no args (NR in R3) */
index 5083b6ed4b39a5b1fe07bb32a9a1e9bc42d47383..e18f183e1035b70864dac90245c60727d9e8d13c 100644 (file)
@@ -314,6 +314,12 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
 #endif
 }
 
+#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#define SYSCALL_ARG3   "trapa #0x23"
+#else
+#define SYSCALL_ARG3   "trapa #0x13"
+#endif
+
 /*
  * Do a system call from kernel instead of calling sys_execve so we
  * end up with proper pt_regs.
@@ -324,7 +330,7 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
        register long __sc4 __asm__ ("r4") = (long) filename;
        register long __sc5 __asm__ ("r5") = (long) argv;
        register long __sc6 __asm__ ("r6") = (long) envp;
-       __asm__ __volatile__ ("trapa    #0x13" : "=z" (__sc0)
+       __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)       
                        : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
                        : "memory");
        return __sc0;
index 3762d9dc20466a026720b1e2821e3c7a4aef8db8..ec110157992df81c91d8b38eddc3e5f4634894b4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kallsyms.h>
 #include <linux/io.h>
 #include <linux/debug_locks.h>
+#include <linux/limits.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -129,6 +130,40 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
        return -EFAULT;
 }
 
+#ifdef CONFIG_BUG
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+static inline void do_bug_verbose(struct pt_regs *regs)
+{
+       struct bug_frame f;
+       long len;
+
+       if (__copy_from_user(&f, (const void __user *)regs->pc,
+                            sizeof(struct bug_frame)))
+               return;
+
+       len = __strnlen_user(f.file, PATH_MAX) - 1;
+       if (unlikely(len < 0 || len >= PATH_MAX))
+               f.file = "<bad filename>";
+       len = __strnlen_user(f.func, PATH_MAX) - 1;
+       if (unlikely(len < 0 || len >= PATH_MAX))
+               f.func = "<bad function>";
+
+       printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
+              f.func, f.file, f.line);
+}
+#else
+static inline void do_bug_verbose(struct pt_regs *regs)
+{
+}
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#endif /* CONFIG_BUG */
+
+void handle_BUG(struct pt_regs *regs)
+{
+       do_bug_verbose(regs);
+       die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
 /*
  * handle an instruction that does an unaligned memory access by emulating the
  * desired behaviour
index 77b4026d5688683820a6ba83388f457a1f860a77..f34bdcc33a7dd5a39124e7f3f1c543b48884353a 100644 (file)
@@ -51,7 +51,7 @@ SECTIONS
        }
 
   . = ALIGN(PAGE_SIZE);
-  .data.page_aligned : { *(.data.idt) }
+  .data.page_aligned : { *(.data.page_aligned) }
 
   . = ALIGN(32);
   __per_cpu_start = .;
index 4e0362f5038468666c546efa9af3b69dd5a79555..29f4ee35c6dc44e356aa0cf59891e0253c71d929 100644 (file)
@@ -35,6 +35,9 @@ config CPU_SUBTYPE_ST40
        select CPU_SH4
        select CPU_HAS_INTC2_IRQ
 
+config CPU_SHX2
+       bool
+
 #
 # Processor subtypes
 #
@@ -180,6 +183,7 @@ config CPU_SUBTYPE_SH7780
 config CPU_SUBTYPE_SH7785
        bool "Support SH7785 processor"
        select CPU_SH4A
+       select CPU_SHX2
        select CPU_HAS_INTC2_IRQ
 
 comment "SH4AL-DSP Processor Support"
@@ -192,6 +196,12 @@ config CPU_SUBTYPE_SH7343
        bool "Support SH7343 processor"
        select CPU_SH4AL_DSP
 
+config CPU_SUBTYPE_SH7722
+       bool "Support SH7722 processor"
+       select CPU_SH4AL_DSP
+       select CPU_SHX2
+       select CPU_HAS_IPR_IRQ
+
 endmenu
 
 menu "Memory management options"
@@ -250,7 +260,7 @@ config 32BIT
 
 config X2TLB
        bool "Enable extended TLB mode"
-       depends on CPU_SUBTYPE_SH7785 && MMU && EXPERIMENTAL
+       depends on CPU_SHX2 && MMU && EXPERIMENTAL
        help
          Selecting this option will enable the extended mode of the SH-X2
          TLB. For legacy SH-X behaviour and interoperability, say N. For
index ae531affccbd75b9a088acbd0623fa2076aebb64..c6955157c9897fc20d43567d09622fcfe6ab2d79 100644 (file)
@@ -107,7 +107,7 @@ void __init p3_cache_init(void)
 
        emit_cache_params();
 
-       if (remap_area_pages(P3SEG, 0, PAGE_SIZE * 4, _PAGE_CACHABLE))
+       if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL))
                panic("%s failed.", __FUNCTION__);
 
        for (i = 0; i < cpu_data->dcache.n_aliases; i++)
index 59f4cc18235b289c2849f4c3b48b72224f85b5fc..29bd37b1488e42ee7e5a74d5beb5cf5ba680b059 100644 (file)
@@ -77,6 +77,7 @@ void show_mem(void)
        printk("%d pages swap cached\n",cached);
 }
 
+#ifdef CONFIG_MMU
 static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
 {
        pgd_t *pgd;
@@ -139,6 +140,7 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
 
        set_pte_phys(address, phys, prot);
 }
+#endif /* CONFIG_MMU */
 
 /* References to section boundaries */
 
index 54d51b404603091e377f1e311df323b64caffc12..cbbc98846b0081cfe322622dcca604a222b207b4 100644 (file)
@@ -317,9 +317,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
        if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0)
                goto err_nopages;
 
-       if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
+       if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
                goto err_nomem;
-       memset((char*)res, 0, sizeof(struct resource));
 
        if (allocate_resource(&_sparc_dvma, res, len_total,
            _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
@@ -589,12 +588,11 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba)
                return NULL;
        }
 
-       if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
+       if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
                free_pages(va, order);
                printk("pci_alloc_consistent: no core\n");
                return NULL;
        }
-       memset((char*)res, 0, sizeof(struct resource));
 
        if (allocate_resource(&_sparc_dvma, res, len_total,
            _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
index 46200c43ffb129a4ed51f3430126d927895d29f4..dab6169e31ca42467a211a7570f863a08e250aff 100644 (file)
@@ -793,10 +793,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
 {
        struct of_device *dev;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       memset(dev, 0, sizeof(*dev));
 
        dev->dev.parent = parent;
        dev->dev.bus = bus;
index 1baf13ed5c3a6b6e7186c022e69108ec6d490c46..003f8eed32f413e8ba835bdcfea2e16d703789c5 100644 (file)
@@ -289,7 +289,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
 
        if (request == PTRACE_TRACEME) {
                ret = ptrace_traceme();
-               pt_succ_return(regs, 0);
+               if (ret < 0)
+                       pt_error_return(regs, -ret);
+               else
+                       pt_succ_return(regs, 0);
                goto out;
        }
 
index d4f9da8170c529c9f26c4d915fe3e37b85244f30..cf1b8baa57eafd4c8b9ae3f7e45fdab3564aa6a1 100644 (file)
@@ -545,8 +545,11 @@ void __init sun4d_init_sbi_irq(void)
        nsbi = 0;
        for_each_sbus(sbus)
                nsbi++;
-       sbus_actions = (struct sbus_action *)kmalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
-       memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
+       sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
+       if (!sbus_actions) {
+               prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
+               prom_halt();
+       }
        for_each_sbus(sbus) {
 #ifdef CONFIG_SMP      
                extern unsigned char boot_cpu_id;
index 2bb1309003dd9e6ba316fdf87df308f2bceb34b5..4ccda77d08d6bf7d180036f09d452b2813784676 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/dma.h>
+#include <asm/oplib.h>
 
 /* #define IOUNIT_DEBUG */
 #ifdef IOUNIT_DEBUG
@@ -41,9 +42,12 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
        struct linux_prom_registers iommu_promregs[PROMREG_MAX];
        struct resource r;
 
-       iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
+       iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
+       if (!iounit) {
+               prom_printf("SUN4D: Cannot alloc iounit, halting.\n");
+               prom_halt();
+       }
 
-       memset(iounit, 0, sizeof(*iounit));
        iounit->limit[0] = IOUNIT_BMAP1_START;
        iounit->limit[1] = IOUNIT_BMAP2_START;
        iounit->limit[2] = IOUNIT_BMAPM_START;
index d391d11f245ab0d8d06ce6a9e92c95a1b4b989f8..d41f66ac7fff71dd8768271775aad6b183de987f 100644 (file)
@@ -26,6 +26,14 @@ config MMU
        bool
        default y
 
+config STACKTRACE_SUPPORT
+       bool
+       default y
+
+config LOCKDEP_SUPPORT
+       bool
+       default y
+
 config TIME_INTERPOLATION
        bool
        default y
index afe0a7720a26492d08e52b40862817c5ac658081..1f130f3b6c24affc675d29425e7a21d9e8cd2ef7 100644 (file)
@@ -1,5 +1,9 @@
 menu "Kernel hacking"
 
+config TRACE_IRQFLAGS_SUPPORT
+       bool
+       default y
+
 source "lib/Kconfig.debug"
 
 config DEBUG_STACK_USAGE
index 2f4612fa81f274e5b61982c350c69f6654118bb7..0f0d38f6197c6844944f8b366d808a9a5e1218bc 100644 (file)
@@ -1,24 +1,29 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc2
-# Tue Oct 17 19:29:20 2006
+# Linux kernel version: 2.6.19
+# Sat Dec  9 15:41:30 2006
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
 CONFIG_64BIT=y
 CONFIG_MMU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_TIME_INTERPOLATION=y
 CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
 CONFIG_SPARC64_PAGE_SIZE_8KB=y
 # CONFIG_SPARC64_PAGE_SIZE_64KB is not set
 # CONFIG_SPARC64_PAGE_SIZE_512KB is not set
 # CONFIG_SPARC64_PAGE_SIZE_4MB is not set
 CONFIG_SECCOMP=y
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
+CONFIG_HZ=100
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -42,13 +47,14 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
 CONFIG_RELAY=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -203,6 +209,7 @@ 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=y
 CONFIG_IPV6_ROUTER_PREF=y
@@ -219,7 +226,6 @@ CONFIG_INET6_XFRM_MODE_BEET=m
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
 CONFIG_IPV6_SIT=m
 CONFIG_IPV6_TUNNEL=m
-# CONFIG_IPV6_SUBTREES is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
@@ -238,6 +244,8 @@ CONFIG_IP_DCCP_CCID2=m
 # CONFIG_IP_DCCP_CCID2_DEBUG is not set
 CONFIG_IP_DCCP_CCID3=m
 CONFIG_IP_DCCP_TFRC_LIB=m
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
 
 #
 # DCCP Kernel Hacking
@@ -405,6 +413,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 CONFIG_RAID_ATTRS=m
 CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
 
@@ -425,6 +434,7 @@ CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
 
 #
 # SCSI Transports
@@ -468,6 +478,7 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SUNESP is not set
+# CONFIG_SCSI_SRP is not set
 
 #
 # Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -598,6 +609,7 @@ CONFIG_BNX2=m
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
 
 #
 # Token Ring devices
@@ -724,10 +736,6 @@ CONFIG_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -1038,6 +1046,11 @@ CONFIG_SND_SUN_CS4231=m
 #
 # CONFIG_SOUND_PRIME is not set
 
+#
+# HID Devices
+#
+CONFIG_HID=y
+
 #
 # USB support
 #
@@ -1053,6 +1066,7 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1089,8 +1103,7 @@ CONFIG_USB_UHCI_HCD=m
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_USB_HID_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -1119,6 +1132,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
 # CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
@@ -1363,6 +1377,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
 #
 # Instrumentation Support
 #
@@ -1373,6 +1392,7 @@ CONFIG_KPROBES=y
 #
 # Kernel hacking
 #
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_PRINTK_TIME=y
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
@@ -1387,6 +1407,8 @@ CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1420,8 +1442,9 @@ CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
 CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_MD5=y
@@ -1430,8 +1453,10 @@ CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_GF128MUL=m
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
@@ -1456,6 +1481,7 @@ CONFIG_CRYPTO_TEST=m
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 CONFIG_CRC16=m
 CONFIG_CRC32=y
index e1eabebaed398134bba3f2be668ac56ae922de30..eff0c01d3579671d2ab8ab54fa79bb9faaedbc4c 100644 (file)
@@ -14,6 +14,7 @@ obj-y         := process.o setup.o cpu.o idprom.o \
                   power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
                   visemul.o prom.o of_device.o
 
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-$(CONFIG_PCI)       += ebus.o isa.o pci_common.o pci_iommu.o \
                            pci_psycho.o pci_sabre.o pci_schizo.o \
                            pci_sun4v.o pci_sun4v_asm.o
index 259f37e516f54f1e82d5c91169ede37faf3382d6..9699abeb9907c2597b8b23bcaccf1cbe2359a04c 100644 (file)
@@ -341,7 +341,7 @@ static void fetch_decode_regs(struct mctrl_info *mp)
 
 static int init_one_mctrl(struct device_node *dp)
 {
-       struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+       struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
        int portid = of_getintprop_default(dp, "portid", -1);
        struct linux_prom64_registers *regs;
        void *pval;
@@ -349,7 +349,6 @@ static int init_one_mctrl(struct device_node *dp)
 
        if (!mp)
                return -1;
-       memset(mp, 0, sizeof(*mp));
        if (portid == -1)
                goto fail;
 
index 6f28bec0a9bf5d4ea8e86806afeb22449099a4c8..c15a3edcb826d93706a69d1bb212fa6269fda6f3 100644 (file)
@@ -597,7 +597,12 @@ __spitfire_cee_trap_continue:
 1:     ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 
-2:     mov             %l4, %o1
+2:
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call    trace_hardirqs_off
+        nop
+#endif
+       mov             %l4, %o1
        mov             %l5, %o2
        call            spitfire_access_error
         add            %sp, PTREGS_OFF, %o0
@@ -824,6 +829,10 @@ do_cheetah_plus_data_parity:
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        mov             0x0, %o0
        call            cheetah_plus_parity_error
         add            %sp, PTREGS_OFF, %o1
@@ -855,6 +864,10 @@ do_cheetah_plus_insn_parity:
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        mov             0x1, %o0
        call            cheetah_plus_parity_error
         add            %sp, PTREGS_OFF, %o1
@@ -1183,6 +1196,10 @@ c_fast_ecc:
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        mov             %l4, %o1
        mov             %l5, %o2
        call            cheetah_fecc_handler
@@ -1211,6 +1228,10 @@ c_cee:
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        mov             %l4, %o1
        mov             %l5, %o2
        call            cheetah_cee_handler
@@ -1239,6 +1260,10 @@ c_deferred:
        wrpr            %g0, 15, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        mov             %l4, %o1
        mov             %l5, %o2
        call            cheetah_deferred_handler
index c8e9dc9d68a9758c62d8e6efc7b5e0a02d88a8e4..03ffaf895a227760fe1ba8e475dcdda56444903b 100644 (file)
@@ -489,6 +489,14 @@ tlb_fixup_done:
        call    __bzero
         sub    %o1, %o0, %o1
 
+#ifdef CONFIG_LOCKDEP
+       /* We have this call this super early, as even prom_init can grab
+        * spinlocks and thus call into the lockdep code.
+        */
+       call    lockdep_init
+        nop
+#endif
+
        mov     %l6, %o1                        ! OpenPROM stack
        call    prom_init
         mov    %l7, %o0                        ! OpenPROM cif handler
index f028e68b23f2acf6b6546d63b39f985db3f10ee5..ad1c4f55420f8b2f456a4ba559a33336b3a55393 100644 (file)
@@ -72,14 +72,12 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
                struct linux_prom_registers *regs;
                struct sparc_isa_device *isa_dev;
 
-               isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+               isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
                if (!isa_dev) {
                        fatal_err("cannot allocate child isa_dev");
                        prom_halt();
                }
 
-               memset(isa_dev, 0, sizeof(*isa_dev));
-
                /* Link it in to parent. */
                isa_dev->next = parent_isa_dev->child;
                parent_isa_dev->child = isa_dev;
@@ -104,14 +102,12 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
                struct linux_prom_registers *regs;
                struct sparc_isa_device *isa_dev;
 
-               isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+               isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
                if (!isa_dev) {
                        printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
                        return;
                }
 
-               memset(isa_dev, 0, sizeof(*isa_dev));
-
                isa_dev->ofdev.node = dp;
                isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
                isa_dev->ofdev.dev.bus = &isa_bus_type;
@@ -180,14 +176,12 @@ void __init isa_init(void)
                pbm = pdev_cookie->pbm;
                dp = pdev_cookie->prom_node;
 
-               isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
+               isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
                if (!isa_br) {
                        printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
                        return;
                }
 
-               memset(isa_br, 0, sizeof(*isa_br));
-
                isa_br->ofdev.node = dp;
                isa_br->ofdev.dev.parent = &pdev->dev;
                isa_br->ofdev.dev.bus = &isa_bus_type;
index 8e75ed762fd80a8555d831c6b324b78282553b6c..ae221f0d4a6f2171ad9e43d83f08ca1cc8d3fa09 100644 (file)
@@ -45,7 +45,11 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        p->ainsn.insn[0] = *p->addr;
+       flushi(&p->ainsn.insn[0]);
+
        p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
+       flushi(&p->ainsn.insn[1]);
+
        p->opcode = *p->addr;
        return 0;
 }
@@ -185,16 +189,19 @@ no_kprobe:
 /* If INSN is a relative control transfer instruction,
  * return the corrected branch destination value.
  *
- * The original INSN location was REAL_PC, it actually
- * executed at PC and produced destination address NPC.
+ * regs->tpc and regs->tnpc still hold the values of the
+ * program counters at the time of trap due to the execution
+ * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1]
+ * 
  */
-static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
-                                              unsigned long pc,
-                                              unsigned long npc)
+static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p,
+                                              struct pt_regs *regs)
 {
+       unsigned long real_pc = (unsigned long) p->addr;
+
        /* Branch not taken, no mods necessary.  */
-       if (npc == pc + 0x4UL)
-               return real_pc + 0x4UL;
+       if (regs->tnpc == regs->tpc + 0x4UL)
+               return real_pc + 0x8UL;
 
        /* The three cases are call, branch w/prediction,
         * and traditional branch.
@@ -202,14 +209,21 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
        if ((insn & 0xc0000000) == 0x40000000 ||
            (insn & 0xc1c00000) == 0x00400000 ||
            (insn & 0xc1c00000) == 0x00800000) {
+               unsigned long ainsn_addr;
+
+               ainsn_addr = (unsigned long) &p->ainsn.insn[0];
+
                /* The instruction did all the work for us
                 * already, just apply the offset to the correct
                 * instruction location.
                 */
-               return (real_pc + (npc - pc));
+               return (real_pc + (regs->tnpc - ainsn_addr));
        }
 
-       return real_pc + 0x4UL;
+       /* It is jmpl or some other absolute PC modification instruction,
+        * leave NPC as-is.
+        */
+       return regs->tnpc;
 }
 
 /* If INSN is an instruction which writes it's PC location
@@ -220,12 +234,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
 {
        unsigned long *slot = NULL;
 
-       /* Simplest cast is call, which always uses %o7 */
+       /* Simplest case is 'call', which always uses %o7 */
        if ((insn & 0xc0000000) == 0x40000000) {
                slot = &regs->u_regs[UREG_I7];
        }
 
-       /* Jmpl encodes the register inside of the opcode */
+       /* 'jmpl' encodes the register inside of the opcode */
        if ((insn & 0xc1f80000) == 0x81c00000) {
                unsigned long rd = ((insn >> 25) & 0x1f);
 
@@ -247,11 +261,11 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
 
 /*
  * Called after single-stepping.  p->addr is the address of the
- * instruction whose first byte has been replaced by the breakpoint
+ * instruction which has been replaced by the breakpoint
  * instruction.  To avoid the SMP problems that can occur when we
  * temporarily put back the original opcode to single-step, we
  * single-stepped a copy of the instruction.  The address of this
- * copy is p->ainsn.insn.
+ * copy is &p->ainsn.insn[0].
  *
  * This function prepares to return from the post-single-step
  * breakpoint trap.
@@ -261,11 +275,11 @@ static void __kprobes resume_execution(struct kprobe *p,
 {
        u32 insn = p->ainsn.insn[0];
 
+       regs->tnpc = relbranch_fixup(insn, p, regs);
+
+       /* This assignment must occur after relbranch_fixup() */
        regs->tpc = kcb->kprobe_orig_tnpc;
-       regs->tnpc = relbranch_fixup(insn,
-                                    (unsigned long) p->addr,
-                                    (unsigned long) &p->ainsn.insn[0],
-                                    regs->tnpc);
+
        retpc_fixup(regs, insn, (unsigned long) p->addr);
 
        regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
@@ -430,17 +444,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
-       kcb->jprobe_saved_regs_location = regs;
        memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
 
-       /* Save a whole stack frame, this gets arguments
-        * pushed onto the stack after using up all the
-        * arg registers.
-        */
-       memcpy(&(kcb->jprobe_saved_stack),
-              (char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
-              sizeof(kcb->jprobe_saved_stack));
-
        regs->tpc  = (unsigned long) jp->entry;
        regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
        regs->tstate |= TSTATE_PIL;
@@ -450,10 +455,19 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 
 void __kprobes jprobe_return(void)
 {
-       __asm__ __volatile__(
-               ".globl jprobe_return_trap_instruction\n"
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       register unsigned long orig_fp asm("g1");
+
+       orig_fp = kcb->jprobe_saved_regs.u_regs[UREG_FP];
+       __asm__ __volatile__("\n"
+"1:    cmp             %%sp, %0\n\t"
+       "blu,a,pt       %%xcc, 1b\n\t"
+       " restore\n\t"
+       ".globl         jprobe_return_trap_instruction\n"
 "jprobe_return_trap_instruction:\n\t"
-               "ta 0x70");
+       "ta             0x70"
+       : /* no outputs */
+       : "r" (orig_fp));
 }
 
 extern void jprobe_return_trap_instruction(void);
@@ -466,26 +480,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
 
        if (addr == (u32 *) jprobe_return_trap_instruction) {
-               if (kcb->jprobe_saved_regs_location != regs) {
-                       printk("JPROBE: Current regs (%p) does not match "
-                              "saved regs (%p).\n",
-                              regs, kcb->jprobe_saved_regs_location);
-                       printk("JPROBE: Saved registers\n");
-                       __show_regs(kcb->jprobe_saved_regs_location);
-                       printk("JPROBE: Current registers\n");
-                       __show_regs(regs);
-                       BUG();
-               }
-               /* Restore old register state.  Do pt_regs
-                * first so that UREG_FP is the original one for
-                * the stack frame restore.
-                */
                memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
-
-               memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
-                      &(kcb->jprobe_saved_stack),
-                      sizeof(kcb->jprobe_saved_stack));
-
                preempt_enable_no_resched();
                return 1;
        }
index 8cc14fc6b6f13ff028489260c1e8aa155c791019..cec0eceae552acab1b561abb58b7cfa00aeebd38 100644 (file)
@@ -1007,10 +1007,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
 {
        struct of_device *dev;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       memset(dev, 0, sizeof(*dev));
 
        dev->dev.parent = parent;
        dev->dev.bus = bus;
index 03ad4c06758ed95fd59d996a11fcc7784bc2c54b..6b04794b7a971bab494b7837748c6bc741bc7e5b 100644 (file)
@@ -798,7 +798,7 @@ static struct pci_ops pci_sun4v_ops = {
 static void pbm_scan_bus(struct pci_controller_info *p,
                         struct pci_pbm_info *pbm)
 {
-       struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+       struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
 
        if (!cookie) {
                prom_printf("%s: Critical allocation failure.\n", pbm->name);
@@ -806,7 +806,6 @@ static void pbm_scan_bus(struct pci_controller_info *p,
        }
 
        /* All we care about is the PBM. */
-       memset(cookie, 0, sizeof(*cookie));
        cookie->pbm = pbm;
 
        pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
@@ -1048,12 +1047,11 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        /* Allocate and initialize the free area map.  */
        sz = num_tsb_entries / 8;
        sz = (sz + 7UL) & ~7UL;
-       iommu->arena.map = kmalloc(sz, GFP_KERNEL);
+       iommu->arena.map = kzalloc(sz, GFP_KERNEL);
        if (!iommu->arena.map) {
                prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
                prom_halt();
        }
-       memset(iommu->arena.map, 0, sz);
        iommu->arena.limit = num_tsb_entries;
 
        sz = probe_existing_entries(pbm, iommu);
@@ -1164,24 +1162,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
                per_cpu(pci_iommu_batch, i).pglist = (u64 *) page;
        }
 
-       p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
        if (!p)
                goto fatal_memory_error;
 
-       memset(p, 0, sizeof(*p));
-
-       iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+       iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
        if (!iommu)
                goto fatal_memory_error;
 
-       memset(iommu, 0, sizeof(*iommu));
        p->pbm_A.iommu = iommu;
 
-       iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+       iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
        if (!iommu)
                goto fatal_memory_error;
 
-       memset(iommu, 0, sizeof(*iommu));
        p->pbm_B.iommu = iommu;
 
        p->next = pci_controller_root;
index d31975e6d6f6bd80aa4b8adee52c5d6a36181239..81111a12f0a83bffe186c418048734f9a3493683 100644 (file)
@@ -202,7 +202,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
 #endif
        if (request == PTRACE_TRACEME) {
                ret = ptrace_traceme();
-               pt_succ_return(regs, 0);
+               if (ret < 0)
+                       pt_error_return(regs, -ret);
+               else
+                       pt_succ_return(regs, 0);
                goto out;
        }
 
index 3522cd66f3bb36e0e1250b4ac7cd9dadebcfb52d..079d18a11d247fcb3ee668e06438004bb500db74 100644 (file)
@@ -165,14 +165,26 @@ rtrap:
 __handle_softirq_continue:
 rtrap_xcall:
                sethi                   %hi(0xf << 20), %l4
-               andcc                   %l1, TSTATE_PRIV, %l3
                and                     %l1, %l4, %l4
+               andn                    %l1, %l4, %l1
+               srl                     %l4, 20, %l4
+#ifdef CONFIG_TRACE_IRQFLAGS
+               brnz,pn                 %l4, rtrap_no_irq_enable
+                nop
+               call                    trace_hardirqs_on
+                nop
+               wrpr                    %l4, %pil
+rtrap_no_irq_enable:
+#endif
+               andcc                   %l1, TSTATE_PRIV, %l3
                bne,pn                  %icc, to_kernel
-                andn                   %l1, %l4, %l1
+                nop
 
                /* We must hold IRQs off and atomically test schedule+signal
                 * state, then hold them off all the way back to userspace.
-                * If we are returning to kernel, none of this matters.
+                * If we are returning to kernel, none of this matters.  Note
+                * that we are disabling interrupts via PSTATE_IE, not using
+                * %pil.
                 *
                 * If we do not do this, there is a window where we would do
                 * the tests, later the signal/resched event arrives but we do
@@ -256,7 +268,6 @@ rt_continue:        ldx                     [%sp + PTREGS_OFF + PT_V9_G1], %g1
 
                ld                      [%sp + PTREGS_OFF + PT_V9_Y], %o3
                wr                      %o3, %g0, %y
-               srl                     %l4, 20, %l4
                wrpr                    %l4, 0x0, %pil
                wrpr                    %g0, 0x1, %tl
                wrpr                    %l1, %g0, %tstate
@@ -374,8 +385,8 @@ to_kernel:
                 ldx                    [%g6 + TI_FLAGS], %l5
                andcc                   %l5, _TIF_NEED_RESCHED, %g0
                be,pt                   %xcc, kern_fpucheck
-                srl                    %l4, 20, %l5
-               cmp                     %l5, 0
+                nop
+               cmp                     %l4, 0
                bne,pn                  %xcc, kern_fpucheck
                 sethi                  %hi(PREEMPT_ACTIVE), %l6
                stw                     %l6, [%g6 + TI_PRE_COUNT]
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..c4d15f2
--- /dev/null
@@ -0,0 +1,41 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+       unsigned long ksp, fp, thread_base;
+       struct thread_info *tp;
+
+       if (!task)
+               task = current;
+       tp = task_thread_info(task);
+       if (task == current) {
+               flushw_all();
+               __asm__ __volatile__(
+                       "mov    %%fp, %0"
+                       : "=r" (ksp)
+               );
+       } else
+               ksp = tp->ksp;
+
+       fp = ksp + STACK_BIAS;
+       thread_base = (unsigned long) tp;
+       do {
+               struct reg_window *rw;
+
+               /* Bogus frame pointer? */
+               if (fp < (thread_base + sizeof(struct thread_info)) ||
+                   fp >= (thread_base + THREAD_SIZE))
+                       break;
+
+               rw = (struct reg_window *) fp;
+               if (trace->skip > 0)
+                       trace->skip--;
+               else
+                       trace->entries[trace->nr_entries++] = rw->ins[7];
+
+               fp = rw->ins[6] + STACK_BIAS;
+       } while (trace->nr_entries < trace->max_entries);
+}
index 49703c3c57694fe45972d36f204ee57f50a3a033..405855dd886bc9f7afd0795b7ca93a496e2a2db6 100644 (file)
@@ -190,7 +190,10 @@ sun4v_res_mondo:
        mov     %g1, %g4
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        /* Log the event.  */
        add     %sp, PTREGS_OFF, %o0
        call    sun4v_resum_error
@@ -216,7 +219,10 @@ sun4v_res_mondo_queue_full:
        wrpr    %g0, 15, %pil
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        call    sun4v_resum_overflow
         add    %sp, PTREGS_OFF, %o0
 
@@ -295,7 +301,10 @@ sun4v_nonres_mondo:
        mov     %g1, %g4
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        /* Log the event.  */
        add     %sp, PTREGS_OFF, %o0
        call    sun4v_nonresum_error
@@ -321,7 +330,10 @@ sun4v_nonres_mondo_queue_full:
        wrpr    %g0, 15, %pil
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        call    sun4v_nonresum_overflow
         add    %sp, PTREGS_OFF, %o0
 
index fe1796c939c395618e945b18b017c75d8717f5ed..ad67784292db6aafe26aedc02e9deb130007da3e 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/sched.h>  /* for jiffies */
+#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/kallsyms.h>
 #include <linux/signal.h>
@@ -1873,6 +1873,16 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
 
        put_cpu();
 
+       if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) {
+               /* If err_type is 0x4, it's a powerdown request.  Do
+                * not do the usual resumable error log because that
+                * makes it look like some abnormal error.
+                */
+               printk(KERN_INFO "Power down request...\n");
+               kill_cad_pid(SIGINT, 1);
+               return;
+       }
+
        sun4v_log_error(regs, &local_copy, cpu,
                        KERN_ERR "RESUMABLE ERROR",
                        &sun4v_resum_oflow_cnt);
@@ -2261,8 +2271,12 @@ void die_if_kernel(char *str, struct pt_regs *regs)
        do_exit(SIGSEGV);
 }
 
+#define VIS_OPCODE_MASK        ((0x3 << 30) | (0x3f << 19))
+#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
+
 extern int handle_popc(u32 insn, struct pt_regs *regs);
 extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
+extern int vis_emul(struct pt_regs *, unsigned int);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
@@ -2287,10 +2301,18 @@ void do_illegal_instruction(struct pt_regs *regs)
                        if (handle_ldf_stq(insn, regs))
                                return;
                } else if (tlb_type == hypervisor) {
-                       extern int vis_emul(struct pt_regs *, unsigned int);
+                       if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
+                               if (!vis_emul(regs, insn))
+                                       return;
+                       } else {
+                               struct fpustate *f = FPUSTATE;
 
-                       if (!vis_emul(regs, insn))
-                               return;
+                               /* XXX maybe verify XFSR bits like
+                                * XXX do_fpother() does?
+                                */
+                               if (do_mathemu(regs, f))
+                                       return;
+                       }
                }
        }
        info.si_signo = SIGILL;
index a9b765271b85f9da4546c846f446ab383cecd781..bc18d480dd1cb958fe4010acef75aa8e8a43a766 100644 (file)
@@ -243,7 +243,7 @@ static inline int ok_for_kernel(unsigned int insn)
        return !floating_point_load_or_store_p(insn);
 }
 
-static void kernel_mna_trap_fault(void)
+static void kernel_mna_trap_fault(int fixup_tstate_asi)
 {
        struct pt_regs *regs = current_thread_info()->kern_una_regs;
        unsigned int insn = current_thread_info()->kern_una_insn;
@@ -274,18 +274,15 @@ static void kernel_mna_trap_fault(void)
        regs->tpc = entry->fixup;
        regs->tnpc = regs->tpc + 4;
 
-       regs->tstate &= ~TSTATE_ASI;
-       regs->tstate |= (ASI_AIUS << 24UL);
+       if (fixup_tstate_asi) {
+               regs->tstate &= ~TSTATE_ASI;
+               regs->tstate |= (ASI_AIUS << 24UL);
+       }
 }
 
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+static void log_unaligned(struct pt_regs *regs)
 {
        static unsigned long count, last_time;
-       enum direction dir = decode_direction(insn);
-       int size = decode_access_size(insn);
-
-       current_thread_info()->kern_una_regs = regs;
-       current_thread_info()->kern_una_insn = insn;
 
        if (jiffies - last_time > 5 * HZ)
                count = 0;
@@ -295,6 +292,28 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                printk("Kernel unaligned access at TPC[%lx] ", regs->tpc);
                print_symbol("%s\n", regs->tpc);
        }
+}
+
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+{
+       enum direction dir = decode_direction(insn);
+       int size = decode_access_size(insn);
+       int orig_asi, asi;
+
+       current_thread_info()->kern_una_regs = regs;
+       current_thread_info()->kern_una_insn = insn;
+
+       orig_asi = asi = decode_asi(insn, regs);
+
+       /* If this is a {get,put}_user() on an unaligned userspace pointer,
+        * just signal a fault and do not log the event.
+        */
+       if (asi == ASI_AIUS) {
+               kernel_mna_trap_fault(0);
+               return;
+       }
+
+       log_unaligned(regs);
 
        if (!ok_for_kernel(insn) || dir == both) {
                printk("Unsupported unaligned load/store trap for kernel "
@@ -302,10 +321,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                unaligned_panic("Kernel does fpu/atomic "
                                "unaligned load/store.", regs);
 
-               kernel_mna_trap_fault();
+               kernel_mna_trap_fault(0);
        } else {
                unsigned long addr, *reg_addr;
-               int orig_asi, asi, err;
+               int err;
 
                addr = compute_effective_address(regs, insn,
                                                 ((insn >> 25) & 0x1f));
@@ -315,7 +334,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                       regs->tpc, dirstrings[dir], addr, size,
                       regs->u_regs[UREG_RETPC]);
 #endif
-               orig_asi = asi = decode_asi(insn, regs);
                switch (asi) {
                case ASI_NL:
                case ASI_AIUPL:
@@ -365,7 +383,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
                        /* Not reached... */
                }
                if (unlikely(err))
-                       kernel_mna_trap_fault();
+                       kernel_mna_trap_fault(1);
                else
                        advance(regs);
        }
index 84fedaa38aae5652b93a6ddab65ca34fe561dbd6..c3fd64706b53f031e7663814a8d41923212b869f 100644 (file)
 /* 001001100 - Permute bytes as specified by GSR.MASK  */
 #define BSHUFFLE_OPF   0x04c
 
-#define VIS_OPCODE_MASK        ((0x3 << 30) | (0x3f << 19))
-#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
-
 #define VIS_OPF_SHIFT  5
 #define VIS_OPF_MASK   (0x1ff << VIS_OPF_SHIFT)
 
@@ -810,9 +807,6 @@ int vis_emul(struct pt_regs *regs, unsigned int insn)
        if (get_user(insn, (u32 __user *) pc))
                return -EFAULT;
 
-       if ((insn & VIS_OPCODE_MASK) != VIS_OPCODE_VAL)
-               return -EINVAL;
-
        opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT;
        switch (opf) {
        default:
index d70b60a3bbccb5340cf517dcf64657eba1927456..737c26923c0963470a6059f3ed80056b9ac04367 100644 (file)
@@ -477,6 +477,10 @@ xcall_sync_tick:
        sethi           %hi(109f), %g7
        b,pt            %xcc, etrap_irq
 109:    or             %g7, %lo(109b), %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        call            smp_synchronize_tick_client
         nop
        clr             %l6
@@ -508,6 +512,10 @@ xcall_report_regs:
        sethi           %hi(109f), %g7
        b,pt            %xcc, etrap_irq
 109:    or             %g7, %lo(109b), %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+       call            trace_hardirqs_off
+        nop
+#endif
        call            __show_regs
         add            %sp, PTREGS_OFF, %o0
        clr             %l6
index 3ac581d1720220cddf2601eed541064352bc3152..d4275537b25b6e8bc814f19215278da2633420f3 100644 (file)
@@ -584,7 +584,7 @@ config SECCOMP
          If unsure, say Y. Only embedded should say N here.
 
 config CC_STACKPROTECTOR
-       bool "Enable -fstack-protector buffer overflow detection (EXPRIMENTAL)"
+       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
          This option turns on the -fstack-protector GCC feature. This
index 4a673f5397a05fbbf5aec90b5067bbafcd8e1ad5..2433d6fc68b14faa4f51b9e841a0b1f9d755f3af 100644 (file)
@@ -225,8 +225,7 @@ out:
 
 static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen,
                                void __user *oldval, size_t __user *oldlenp,
-                               void __user *newval, size_t newlen,
-                               void **context)
+                               void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
index 9eccfbd1b536a4850132a7ead6a814d828f086f6..2e74cb0b7807fd986fa4993e9baf4044f8c015f9 100644 (file)
@@ -48,25 +48,10 @@ menu "Processor type and features"
 
 choice
        prompt "Xtensa Processor Configuration"
-       default XTENSA_CPU_LINUX_BE
+       default XTENSA_VARIANT_FSF
 
-config XTENSA_CPU_LINUX_BE
-       bool "linux_be"
-       ---help---
-         The linux_be processor configuration is the baseline Xtensa
-         configurations included in this kernel and also used by
-         binutils, gcc, and gdb. It contains no TIE, no coprocessors,
-         and the following configuration options:
-
-         Code Density Option                2 Misc Special Registers
-         NSA/NSAU Instructions              128-bit Data Bus Width
-         Processor ID                       8K, 2-way I and D Caches
-         Zero-Overhead Loops                2 Inst Address Break Registers
-         Big Endian                         2 Data Address Break Registers
-         64 General-Purpose Registers       JTAG Interface and Trace Port
-         17 Interrupts                      MMU w/ TLBs and Autorefill
-         3 Interrupt Levels                 8 Autorefill Ways (I/D TLBs)
-         3 Timers                           Unaligned Exceptions
+config XTENSA_VARIANT_FSF
+       bool "fsf"
 endchoice
 
 config MMU
index 3a3a4c66ef87585903e9f85dec3f5859467021ff..95f836db38fa3129cd10f2574c2c8cdf1000df79 100644 (file)
 # this architecture
 
 # Core configuration.
-# (Use CPU=<xtensa_config> to use another default compiler.)
+# (Use VAR=<xtensa_config> to use another default compiler.)
 
-cpu-$(CONFIG_XTENSA_CPU_LINUX_BE)      := linux_be
-cpu-$(CONFIG_XTENSA_CPU_LINUX_CUSTOM)  := linux_custom
+variant-$(CONFIG_XTENSA_VARIANT_FSF)           := fsf
+variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM)  := custom
 
-CPU = $(cpu-y)
-export CPU
+VARIANT = $(variant-y)
+export VARIANT
 
 # Platform configuration
 
@@ -27,8 +27,6 @@ platform-$(CONFIG_XTENSA_PLATFORM_ISS)                := iss
 PLATFORM = $(platform-y)
 export PLATFORM
 
-CPPFLAGS       += $(if $(KBUILD_SRC),-I$(srctree)/include/asm-xtensa/)
-CPPFLAGS       += -Iinclude/asm
 CFLAGS         += -pipe -mlongcalls
 
 KBUILD_DEFCONFIG := iss_defconfig
@@ -41,12 +39,12 @@ core-$(CONFIG_EMBEDDED_RAMDISK)     += arch/xtensa/boot/ramdisk/
 
 # Test for cross compiling
 
-ifneq ($(CPU),)
+ifneq ($(VARIANT),)
   COMPILE_ARCH = $(shell uname -m)
 
   ifneq ($(COMPILE_ARCH), xtensa)
     ifndef CROSS_COMPILE
-      CROSS_COMPILE = xtensa_$(CPU)-
+      CROSS_COMPILE = xtensa_$(VARIANT)-
     endif
   endif
 endif
@@ -68,14 +66,13 @@ archinc             := include/asm-xtensa
 
 archprepare: $(archinc)/.platform
 
-# Update machine cpu and platform symlinks if something which affects
+# Update processor variant and platform symlinks if something which affects
 # them changed.
 
 $(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/auto.conf
-       @echo '  SYMLINK $(archinc)/xtensa/config -> $(archinc)/xtensa/config-$(CPU)'
+       @echo '  SYMLINK $(archinc)/variant -> $(archinc)/variant-$(VARIANT)'
        $(Q)mkdir -p $(archinc)
-       $(Q)mkdir -p $(archinc)/xtensa
-       $(Q)ln -fsn $(srctree)/$(archinc)/xtensa/config-$(CPU) $(archinc)/xtensa/config
+       $(Q)ln -fsn $(srctree)/$(archinc)/variant-$(VARIANT) $(archinc)/variant
        @echo '  SYMLINK $(archinc)/platform -> $(archinc)/platform-$(PLATFORM)'
        $(Q)ln -fsn $(srctree)/$(archinc)/platform-$(PLATFORM) $(archinc)/platform
        @touch $@
@@ -89,7 +86,7 @@ zImage zImage.initrd: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
 CLEAN_FILES    += arch/xtensa/vmlinux.lds                      \
-                  $(archinc)/platform $(archinc)/xtensa/config \
+                  $(archinc)/platform $(archinc)/variant       \
                   $(archinc)/.platform
 
 define archhelp
index f857fc760aa87003102d54b50606a30395e2b7e9..464298bc348bc38fb9662830ab0e1b9395eea25a 100644 (file)
@@ -1,7 +1,4 @@
 
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/core.h>
-
 #include <asm/bootparam.h>
 
 
index ee636b0da81c31a15ac45c91616405c5b2cc5e68..84848123e2a8af6d147abb9e78a2b6bbfe372bb6 100644 (file)
@@ -1,9 +1,7 @@
-
-#define _ASMLANGUAGE
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/core.h>
-#include <xtensa/cacheasm.h>
-
+#include <asm/variant/core.h>
+#include <asm/regs.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheasm.h>
        /*
         * RB-Data: RedBoot data/bss
         * P:       Boot-Parameters
@@ -77,8 +75,14 @@ _start:
        /* Note: The assembler cannot relax "addi a0, a0, ..." to an
           l32r, so we load to a4 first. */
 
-       addi    a4, a0, __start - __start_a0
-       mov     a0, a4
+       # addi  a4, a0, __start - __start_a0
+       # mov   a0, a4
+
+       movi    a4, __start
+       movi    a5, __start_a0
+       add     a4, a0, a4
+       sub     a0, a4, a5
+
        movi    a4, __start
        movi    a5, __reloc_end
 
@@ -106,9 +110,13 @@ _start:
        /* We have to flush and invalidate the caches here before we jump. */
 
 #if XCHAL_DCACHE_IS_WRITEBACK
-       dcache_writeback_all  a5, a6
+
+       ___flush_dcache_all a5 a6
+
 #endif
-       icache_invalidate_all a5, a6
+
+       ___invalidate_icache_all a5 a6
+       isync
 
        movi    a11, _reloc
        jx      a11
@@ -209,9 +217,14 @@ _reloc:
        /* jump to the kernel */
 2:
 #if XCHAL_DCACHE_IS_WRITEBACK
-       dcache_writeback_all a5, a6
+
+       ___flush_dcache_all a5 a6
+
 #endif
-       icache_invalidate_all a5, a6
+
+       ___invalidate_icache_all a5 a6
+
+       isync
 
        movi    a5, __start
        movi    a3, boot_initrd_start
index 802621dd48679f32f831c4ff871820a86f3146c4..f19854035e613e44b673ee76b8e0279dc29aae6a 100644 (file)
@@ -53,11 +53,7 @@ CONFIG_CC_ALIGN_JUMPS=0
 #
 # Processor type and features
 #
-CONFIG_XTENSA_ARCH_LINUX_BE=y
-# CONFIG_XTENSA_ARCH_LINUX_LE is not set
-# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
-# CONFIG_XTENSA_ARCH_S5 is not set
-# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_XTENSA_VARIANT_FSF=y
 CONFIG_MMU=y
 # CONFIG_XTENSA_UNALIGNED_USER is not set
 # CONFIG_PREEMPT is not set
index a4956578a24df35269c72e018e4fee936253d4ec..33d6e9d2e83ca10ec0301689457727c27fb58ec7 100644 (file)
  */
 
 #include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm/ptrace.h>
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
-#include <asm/pgtable.h>
 #include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/thread_info.h>
 
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
 
@@ -216,7 +211,7 @@ ENTRY(fast_unaligned)
 
        extui   a5, a4, INSN_OP0, 4     # get insn.op0 nibble
 
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
        _beqi   a5, OP0_L32I_N, .Lload  # L32I.N, jump
        addi    a6, a5, -OP0_S32I_N
        _beqz   a6, .Lstore             # S32I.N, do a store
@@ -251,7 +246,7 @@ ENTRY(fast_unaligned)
 #endif
        __src_b a3, a5, a6              # a3 has the data word
 
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
        addi    a7, a7, 2               # increment PC (assume 16-bit insn)
 
        extui   a5, a4, INSN_OP0, 4
@@ -279,14 +274,14 @@ ENTRY(fast_unaligned)
 
 1:
 
-#if XCHAL_HAVE_LOOP
-       rsr     a3, LEND                # check if we reached LEND
-       bne     a7, a3, 1f
-       rsr     a3, LCOUNT              # and LCOUNT != 0
-       beqz    a3, 1f
-       addi    a3, a3, -1              # decrement LCOUNT and set
+#if XCHAL_HAVE_LOOPS
+       rsr     a5, LEND                # check if we reached LEND
+       bne     a7, a5, 1f
+       rsr     a5, LCOUNT              # and LCOUNT != 0
+       beqz    a5, 1f
+       addi    a5, a5, -1              # decrement LCOUNT and set
        rsr     a7, LBEG                # set PC to LBEGIN
-       wsr     a3, LCOUNT
+       wsr     a5, LCOUNT
 #endif
 
 1:     wsr     a7, EPC_1               # skip load instruction
@@ -336,7 +331,7 @@ ENTRY(fast_unaligned)
 
        movi    a6, 0                   # mask: ffffffff:00000000
 
-#if XCHAL_HAVE_NARROW
+#if XCHAL_HAVE_DENSITY
        addi    a7, a7, 2               # incr. PC,assume 16-bit instruction
 
        extui   a5, a4, INSN_OP0, 4     # extract OP0
@@ -359,14 +354,14 @@ ENTRY(fast_unaligned)
        /* Get memory address */
 
 1:
-#if XCHAL_HAVE_LOOP
-       rsr     a3, LEND                # check if we reached LEND
-       bne     a7, a3, 1f
-       rsr     a3, LCOUNT              # and LCOUNT != 0
-       beqz    a3, 1f
-       addi    a3, a3, -1              # decrement LCOUNT and set
+#if XCHAL_HAVE_LOOPS
+       rsr     a4, LEND                # check if we reached LEND
+       bne     a7, a4, 1f
+       rsr     a4, LCOUNT              # and LCOUNT != 0
+       beqz    a4, 1f
+       addi    a4, a4, -1              # decrement LCOUNT and set
        rsr     a7, LBEG                # set PC to LBEGIN
-       wsr     a3, LCOUNT
+       wsr     a4, LCOUNT
 #endif
 
 1:     wsr     a7, EPC_1               # skip store instruction
@@ -416,6 +411,7 @@ ENTRY(fast_unaligned)
 
        /* Restore working register */
 
+       l32i    a8, a2, PT_AREG8
        l32i    a7, a2, PT_AREG7
        l32i    a6, a2, PT_AREG6
        l32i    a5, a2, PT_AREG5
@@ -446,7 +442,7 @@ ENTRY(fast_unaligned)
        mov     a1, a2
 
        rsr     a0, PS
-        bbsi.l  a2, PS_UM_SHIFT, 1f     # jump if user mode
+        bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
 
        movi    a0, _kernel_exception
        jx      a0
index 7cd1d7f8f608f4df52317d5e85976df79e69c6bd..b256cfbef3447bfcc647904e7ccc1c6cdd123f21 100644 (file)
@@ -87,6 +87,11 @@ int main(void)
        DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
        BLANK();
        DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+
+       /* constants */
+       DEFINE(_CLONE_VM, CLONE_VM);
+       DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
+
        return 0;
 }
 
index cf5a93fb6a2e5ddc37071985f0dec68651c508f6..01bcb9fcfcbdba96dc35f1e8c081455ac5539f5c 100644 (file)
@@ -90,7 +90,6 @@ ENTRY(enable_coprocessor)
        rsync
        retw
 
-#endif
 
 ENTRY(save_coprocessor_extra)
        entry   sp, 16
@@ -197,4 +196,5 @@ _xtensa_reginfo_tables:
        XCHAL_CP7_SA_CONTENTS_LIBDB
        .word   0xFC000000      /* invalid register number,marks end of table*/
 _xtensa_reginfo_table_end:
+#endif
 
index 89e409e9e0dedd9cbb51474aa41359ddfb9631c0..9e271ba009bfd88645008e0adca5d7b3e87a4e0d 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/signal.h>
-#include <xtensa/coreasm.h>
+#include <asm/tlbflush.h>
 
 /* Unimplemented features. */
 
@@ -364,7 +364,7 @@ common_exception:
        movi    a2, 1
        extui   a3, a3, 0, 1            # a3 = PS.INTLEVEL[0]
        moveqz  a3, a2, a0              # a3 = 1 iff interrupt exception
-       movi    a2, PS_WOE_MASK
+       movi    a2, 1 << PS_WOE_BIT
        or      a3, a3, a2
        rsr     a0, EXCCAUSE
        xsr     a3, PS
@@ -399,7 +399,7 @@ common_exception_return:
        /* Jump if we are returning from kernel exceptions. */
 
 1:     l32i    a3, a1, PT_PS
-       _bbsi.l a3, PS_UM_SHIFT, 2f
+       _bbsi.l a3, PS_UM_BIT, 2f
        j       kernel_exception_exit
 
        /* Specific to a user exception exit:
@@ -422,7 +422,7 @@ common_exception_return:
         *       (Hint: There is only one user exception frame on stack)
         */
 
-       movi    a3, PS_WOE_MASK
+       movi    a3, 1 << PS_WOE_BIT
 
        _bbsi.l a4, TIF_NEED_RESCHED, 3f
        _bbci.l a4, TIF_SIGPENDING, 4f
@@ -694,7 +694,7 @@ common_exception_exit:
 ENTRY(debug_exception)
 
        rsr     a0, EPS + XCHAL_DEBUGLEVEL
-       bbsi.l  a0, PS_EXCM_SHIFT, 1f   # exception mode
+       bbsi.l  a0, PS_EXCM_BIT, 1f     # exception mode
 
        /* Set EPC_1 and EXCCAUSE */
 
@@ -707,7 +707,7 @@ ENTRY(debug_exception)
 
        /* Restore PS to the value before the debug exc but with PS.EXCM set.*/
 
-       movi    a2, 1 << PS_EXCM_SHIFT
+       movi    a2, 1 << PS_EXCM_BIT
        or      a2, a0, a2
        movi    a0, debug_exception     # restore a3, debug jump vector
        wsr     a2, PS
@@ -715,7 +715,7 @@ ENTRY(debug_exception)
 
        /* Switch to kernel/user stack, restore jump vector, and save a0 */
 
-       bbsi.l  a2, PS_UM_SHIFT, 2f     # jump if user mode
+       bbsi.l  a2, PS_UM_BIT, 2f       # jump if user mode
 
        addi    a2, a1, -16-PT_SIZE     # assume kernel stack
        s32i    a0, a2, PT_AREG0
@@ -778,7 +778,7 @@ ENTRY(unrecoverable_exception)
        wsr     a1, WINDOWBASE
        rsync
 
-       movi    a1, PS_WOE_MASK | 1
+       movi    a1, (1 << PS_WOE_BIT) | 1
        wsr     a1, PS
        rsync
 
@@ -1004,13 +1004,10 @@ ENTRY(fast_syscall_kernel)
 
        rsr     a0, DEPC                        # get syscall-nr
        _beqz   a0, fast_syscall_spill_registers
-
-       addi    a0, a0, -__NR_sysxtensa
-       _beqz   a0, fast_syscall_sysxtensa
+       _beqi   a0, __NR_xtensa, fast_syscall_xtensa
 
        j       kernel_exception
 
-
 ENTRY(fast_syscall_user)
 
        /* Skip syscall. */
@@ -1024,9 +1021,7 @@ ENTRY(fast_syscall_user)
 
        rsr     a0, DEPC                        # get syscall-nr
        _beqz   a0, fast_syscall_spill_registers
-
-       addi    a0, a0, -__NR_sysxtensa
-       _beqz   a0, fast_syscall_sysxtensa
+       _beqi   a0, __NR_xtensa, fast_syscall_xtensa
 
        j       user_exception
 
@@ -1047,18 +1042,19 @@ ENTRY(fast_syscall_unrecoverable)
 /*
  * sysxtensa syscall handler
  *
- * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
- * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
- * a2                    a6              a3    a4      a5
+ * int sysxtensa (SYS_XTENSA_ATOMIC_SET,     ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_ADD,     ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ *        a2            a6                   a3    a4      a5
  *
  * Entry condition:
  *
- *   a0:       trashed, original value saved on stack (PT_AREG0)
+ *   a0:       a2 (syscall-nr), original value saved on stack (PT_AREG0)
  *   a1:       a1
- *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a2:       new stack pointer, original in a0 and DEPC
+ *   a3:       dispatch table, original in excsave_1
+ *   a4..a15:  unchanged
  *   depc:     a2, original value saved on stack (PT_DEPC)
  *   excsave_1:        a3
  *
@@ -1091,59 +1087,62 @@ ENTRY(fast_syscall_unrecoverable)
 #define CATCH                                                          \
 67:
 
-ENTRY(fast_syscall_sysxtensa)
-
-       _beqz   a6, 1f
-       _blti   a6, SYSXTENSA_COUNT, 2f
+ENTRY(fast_syscall_xtensa)
 
-1:     j       user_exception
-
-2:     xsr     a3, EXCSAVE_1           # restore a3, excsave1
-       s32i    a7, a2, PT_AREG7
+       xsr     a3, EXCSAVE_1           # restore a3, excsave1
 
+       s32i    a7, a2, PT_AREG7        # we need an additional register
        movi    a7, 4                   # sizeof(unsigned int)
-       access_ok a0, a3, a7, a2, .Leac
+       access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
 
-       _beqi   a6, SYSXTENSA_ATOMIC_SET, .Lset
-       _beqi   a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
-       _beqi   a6, SYSXTENSA_ATOMIC_ADD, .Ladd
+       addi    a6, a6, -1              # assuming SYS_XTENSA_ATOMIC_SET = 1
+       _bgeui  a6, SYS_XTENSA_COUNT - 1, .Lill
+       _bnei   a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp
 
-       /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
+       /* Fall through for ATOMIC_CMP_SWP. */
 
 .Lswp: /* Atomic compare and swap */
 
-TRY    l32i    a7, a3, 0               # read old value
-       bne     a7, a4, 1f              # same as old value? jump
-       s32i    a5, a3, 0               # different, modify value
-       movi    a7, 1                   # and return 1
-       j       .Lret
-
-1:     movi    a7, 0                   # same values: return 0
-       j       .Lret
-
-.Ladd: /* Atomic add */
-.Lexg: /* Atomic (exchange) add */
+TRY    l32i    a0, a3, 0               # read old value
+       bne     a0, a4, 1f              # same as old value? jump
+TRY    s32i    a5, a3, 0               # different, modify value
+       l32i    a7, a2, PT_AREG7        # restore a7
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, 1                   # and return 1
+       addi    a6, a6, 1               # restore a6 (really necessary?)
+       rfe
 
-TRY    l32i    a7, a3, 0
-       add     a4, a4, a7
-       s32i    a4, a3, 0
-       j       .Lret
+1:     l32i    a7, a2, PT_AREG7        # restore a7
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, 0                   # return 0 (note that we cannot set
+       addi    a6, a6, 1               # restore a6 (really necessary?)
+       rfe
 
-.Lset: /* Atomic set */
+.Lnswp:        /* Atomic set, add, and exg_add. */
 
-TRY    l32i    a7, a3, 0               # read old value as return value
-       s32i    a4, a3, 0               # write new value
+TRY    l32i    a7, a3, 0               # orig
+       add     a0, a4, a7              # + arg
+       moveqz  a0, a4, a6              # set
+TRY    s32i    a0, a3, 0               # write new value
 
-.Lret: mov     a0, a2
+       mov     a0, a2
        mov     a2, a7
-       l32i    a7, a0, PT_AREG7
-       l32i    a3, a0, PT_AREG3
-       l32i    a0, a0, PT_AREG0
+       l32i    a7, a0, PT_AREG7        # restore a7
+       l32i    a0, a0, PT_AREG0        # restore a0
+       addi    a6, a6, 1               # restore a6 (really necessary?)
        rfe
 
 CATCH
-.Leac: movi    a7, -EFAULT
-       j       .Lret
+.Leac: l32i    a7, a2, PT_AREG7        # restore a7
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, -EFAULT
+       rfe
+
+.Lill: l32i    a7, a2, PT_AREG0        # restore a7
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, -EINVAL
+       rfe
+
 
 
 
@@ -1491,7 +1490,7 @@ ENTRY(_spill_registers)
         */
 
        rsr     a0, PS
-       _bbci.l a0, PS_UM_SHIFT, 1f
+       _bbci.l a0, PS_UM_BIT, 1f
 
        /* User space: Setup a dummy frame and kill application.
         * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
@@ -1510,7 +1509,7 @@ ENTRY(_spill_registers)
        l32i    a1, a3, EXC_TABLE_KSTK
        wsr     a3, EXCSAVE_1
 
-       movi    a4, PS_WOE_MASK | 1
+       movi    a4, (1 << PS_WOE_BIT) | 1
        wsr     a4, PS
        rsync
 
@@ -1612,7 +1611,7 @@ ENTRY(fast_second_level_miss)
        rsr     a1, PTEVADDR
        srli    a1, a1, PAGE_SHIFT
        slli    a1, a1, PAGE_SHIFT      # ptevaddr & PAGE_MASK
-       addi    a1, a1, DTLB_WAY_PGTABLE        # ... + way_number
+       addi    a1, a1, DTLB_WAY_PGD    # ... + way_number
 
        wdtlb   a0, a1
        dsync
@@ -1654,7 +1653,7 @@ ENTRY(fast_second_level_miss)
        mov     a1, a2
 
        rsr     a2, PS
-       bbsi.l  a2, PS_UM_SHIFT, 1f
+       bbsi.l  a2, PS_UM_BIT, 1f
        j       _kernel_exception
 1:     j       _user_exception
 
@@ -1753,7 +1752,7 @@ ENTRY(fast_store_prohibited)
        mov     a1, a2
 
        rsr     a2, PS
-       bbsi.l  a2, PS_UM_SHIFT, 1f
+       bbsi.l  a2, PS_UM_BIT, 1f
        j       _kernel_exception
 1:     j       _user_exception
 
@@ -1906,6 +1905,103 @@ ENTRY(fast_coprocessor)
 
 #endif /* XCHAL_EXTRA_SA_SIZE */
 
+/*
+ * System Calls.
+ *
+ * void system_call (struct pt_regs* regs, int exccause)
+ *                            a2                 a3
+ */
+
+ENTRY(system_call)
+       entry   a1, 32
+
+       /* regs->syscall = regs->areg[2] */
+
+       l32i    a3, a2, PT_AREG2
+       mov     a6, a2
+       movi    a4, do_syscall_trace_enter
+       s32i    a3, a2, PT_SYSCALL
+       callx4  a4
+
+       /* syscall = sys_call_table[syscall_nr] */
+
+       movi    a4, sys_call_table;
+       movi    a5, __NR_syscall_count
+       movi    a6, -ENOSYS
+       bgeu    a3, a5, 1f
+
+       addx4   a4, a3, a4
+       l32i    a4, a4, 0
+       movi    a5, sys_ni_syscall;
+       beq     a4, a5, 1f
+
+       /* Load args: arg0 - arg5 are passed via regs. */
+
+       l32i    a6, a2, PT_AREG6
+       l32i    a7, a2, PT_AREG3
+       l32i    a8, a2, PT_AREG4
+       l32i    a9, a2, PT_AREG5
+       l32i    a10, a2, PT_AREG8
+       l32i    a11, a2, PT_AREG9
+
+       /* Pass one additional argument to the syscall: pt_regs (on stack) */
+       s32i    a2, a1, 0
+
+       callx4  a4
+
+1:     /* regs->areg[2] = return_value */
+
+       s32i    a6, a2, PT_AREG2
+       movi    a4, do_syscall_trace_leave
+       mov     a6, a2
+       callx4  a4
+       retw
+
+
+/*
+ * Create a kernel thread
+ *
+ * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+ * a2                    a2                 a3             a4
+ */
+
+ENTRY(kernel_thread)
+       entry   a1, 16
+
+       mov     a5, a2                  # preserve fn over syscall
+       mov     a7, a3                  # preserve args over syscall
+
+       movi    a3, _CLONE_VM | _CLONE_UNTRACED
+       movi    a2, __NR_clone
+       or      a6, a4, a3              # arg0: flags
+       mov     a3, a1                  # arg1: sp
+       syscall
+
+       beq     a3, a1, 1f              # branch if parent
+       mov     a6, a7                  # args
+       callx4  a5                      # fn(args)
+
+       movi    a2, __NR_exit
+       syscall                         # return value of fn(args) still in a6
+
+1:     retw
+
+/*
+ * Do a system call from kernel instead of calling sys_execve, so we end up
+ * with proper pt_regs.
+ *
+ * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
+ * a2                        a2               a3                  a4
+ */
+
+ENTRY(kernel_execve)
+       entry   a1, 16
+       mov     a6, a2                  # arg0 is in a6
+       movi    a2, __NR_execve
+       syscall
+
+       retw
+
 /*
  * Task switch.
  *
@@ -1924,7 +2020,7 @@ ENTRY(_switch_to)
 
        /* Disable ints while we manipulate the stack pointer; spill regs. */
 
-       movi    a5, PS_EXCM_MASK | LOCKLEVEL
+       movi    a5, (1 << PS_EXCM_BIT) | LOCKLEVEL
        xsr     a5, PS
        rsr     a3, EXCSAVE_1
        rsync
@@ -1964,33 +2060,9 @@ ENTRY(ret_from_fork)
        movi    a4, schedule_tail
        callx4  a4
 
-       movi    a4, do_syscall_trace
+       movi    a4, do_syscall_trace_leave
+       mov     a6, a1
        callx4  a4
 
        j       common_exception_return
 
-
-
-/*
- * Table of syscalls
- */
-
-.data
-.align  4
-.global sys_call_table
-sys_call_table:
-
-#define SYSCALL(call, narg) .word call
-#include "syscalls.h"
-
-/*
- * Number of arguments of each syscall
- */
-
-.global sys_narg_table
-sys_narg_table:
-
-#undef SYSCALL
-#define SYSCALL(call, narg) .byte narg
-#include "syscalls.h"
-
index c07cb25229931b1198895c291947c59c8ce3e4e9..ea89910efa44f523e928ffc6a1b33938e5e97d45 100644 (file)
@@ -15,9 +15,9 @@
  * Kevin Chea
  */
 
-#include <xtensa/cacheasm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/cacheasm.h>
 
 /*
  * This module contains the entry code for kernel images. It performs the
  *
  */
 
-       .macro  iterate from, to , cmd
-               .ifeq   ((\to - \from) & ~0xfff)
-                       \cmd    \from
-                       iterate "(\from+1)", \to, \cmd
-               .endif
-       .endm
-
 /*
  *  _start
  *
@@ -64,7 +57,7 @@ _startup:
 
        /* Disable interrupts and exceptions. */
 
-       movi    a0, XCHAL_PS_EXCM_MASK
+       movi    a0, LOCKLEVEL
        wsr     a0, PS
 
        /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
@@ -91,11 +84,11 @@ _startup:
        movi    a1, 15
        wsr     a0, ICOUNTLEVEL
 
-       .macro reset_dbreak num
-       wsr     a0, DBREAKC + \num
-       .endm
-
-        iterate 0, XCHAL_NUM_IBREAK-1, reset_dbreak
+       .set    _index, 0
+       .rept   XCHAL_NUM_DBREAK - 1
+       wsr     a0, DBREAKC + _index
+       .set    _index, _index + 1
+       .endr
 #endif
 
        /* Clear CCOUNT (not really necessary, but nice) */
@@ -110,10 +103,11 @@ _startup:
 
        /* Disable all timers. */
 
-       .macro  reset_timer     num
-       wsr     a0, CCOMPARE_0 + \num
-       .endm
-       iterate 0, XCHAL_NUM_TIMERS-1, reset_timer
+       .set    _index, 0
+       .rept   XCHAL_NUM_TIMERS - 1
+       wsr     a0, CCOMPARE + _index
+       .set    _index, _index + 1
+       .endr
 
        /* Interrupt initialization. */
 
@@ -139,12 +133,21 @@ _startup:
        rsync
 
        /*  Initialize the caches.
-        *  Does not include flushing writeback d-cache.
-        *  a6, a7 are just working registers (clobbered).
+        *  a2, a3 are just working registers (clobbered).
         */
 
-       icache_reset  a2, a3
-       dcache_reset  a2, a3
+#if XCHAL_DCACHE_LINE_LOCKABLE
+       ___unlock_dcache_all a2 a3
+#endif
+
+#if XCHAL_ICACHE_LINE_LOCKABLE
+       ___unlock_icache_all a2 a3
+#endif
+
+       ___invalidate_dcache_all a2 a3
+       ___invalidate_icache_all a2 a3
+
+       isync
 
        /* Unpack data sections
         *
@@ -181,9 +184,9 @@ _startup:
        movi    a2, _bss_start  # start of BSS
        movi    a3, _bss_end    # end of BSS
 
-1:     addi    a2, a2, 4
+       __loopt a2, a3, a4, 2
        s32i    a0, a2, 0
-       blt     a2, a3, 1b
+       __endla a2, a4, 4
 
 #if XCHAL_DCACHE_IS_WRITEBACK
 
@@ -191,7 +194,7 @@ _startup:
         * instructions/data are available.
         */
 
-       dcache_writeback_all    a2, a3
+       ___flush_dcache_all a2 a3
 #endif
 
        /* Setup stack and enable window exceptions (keep irqs disabled) */
index 1cf744ee0959e2515d5c47ebcbaffb9e6ac9fba3..c9ea73b7031b837561f225168cc71c0af420a672 100644 (file)
@@ -4,7 +4,7 @@
  * Xtensa built-in interrupt controller and some generic functions copied
  * from i386.
  *
- * Copyright (C) 2002 - 2005 Tensilica, Inc.
+ * Copyright (C) 2002 - 2006 Tensilica, Inc.
  * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  *
  *
 #include <asm/uaccess.h>
 #include <asm/platform.h>
 
-static void enable_xtensa_irq(unsigned int irq);
-static void disable_xtensa_irq(unsigned int irq);
-static void mask_and_ack_xtensa(unsigned int irq);
-static void end_xtensa_irq(unsigned int irq);
-
 static unsigned int cached_irq_mask;
 
 atomic_t irq_err_count;
@@ -46,8 +41,16 @@ void ack_bad_irq(unsigned int irq)
  * handlers).
  */
 
-unsigned int  do_IRQ(int irq, struct pt_regs *regs)
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
 {
+       struct pt_regs *old_regs = set_irq_regs(regs);
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                               __FUNCTION__, irq);
+       }
+
        irq_enter();
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
@@ -63,12 +66,10 @@ unsigned int  do_IRQ(int irq, struct pt_regs *regs)
                               sp - sizeof(struct thread_info));
        }
 #endif
-
-       __do_IRQ(irq, regs);
+       desc->handle_irq(irq, desc);
 
        irq_exit();
-
-       return 1;
+       set_irq_regs(old_regs);
 }
 
 /*
@@ -118,72 +119,68 @@ skip:
        }
        return 0;
 }
-/* shutdown is same as "disable" */
-#define shutdown_xtensa_irq disable_xtensa_irq
 
-static unsigned int startup_xtensa_irq(unsigned int irq)
-{
-       enable_xtensa_irq(irq);
-       return 0;               /* never anything pending */
-}
-
-static struct hw_interrupt_type xtensa_irq_type = {
-       "Xtensa-IRQ",
-       startup_xtensa_irq,
-       shutdown_xtensa_irq,
-       enable_xtensa_irq,
-       disable_xtensa_irq,
-       mask_and_ack_xtensa,
-       end_xtensa_irq
-};
-
-static inline void mask_irq(unsigned int irq)
+static void xtensa_irq_mask(unsigned int irq)
 {
        cached_irq_mask &= ~(1 << irq);
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static inline void unmask_irq(unsigned int irq)
+static void xtensa_irq_unmask(unsigned int irq)
 {
        cached_irq_mask |= 1 << irq;
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static void disable_xtensa_irq(unsigned int irq)
+static void xtensa_irq_ack(unsigned int irq)
 {
-       unsigned long flags;
-       local_save_flags(flags);
-       mask_irq(irq);
-       local_irq_restore(flags);
+       set_sr(1 << irq, INTCLEAR);
 }
 
-static void enable_xtensa_irq(unsigned int irq)
+static int xtensa_irq_retrigger(unsigned int irq)
 {
-       unsigned long flags;
-       local_save_flags(flags);
-       unmask_irq(irq);
-       local_irq_restore(flags);
-}
-
-static void mask_and_ack_xtensa(unsigned int irq)
-{
-        disable_xtensa_irq(irq);
+       set_sr (1 << irq, INTSET);
+       return 1;
 }
 
-static void end_xtensa_irq(unsigned int irq)
-{
-        enable_xtensa_irq(irq);
-}
 
+static struct irq_chip xtensa_irq_chip = {
+       .name           = "xtensa",
+       .mask           = xtensa_irq_mask,
+       .unmask         = xtensa_irq_unmask,
+       .ack            = xtensa_irq_ack,
+       .retrigger      = xtensa_irq_retrigger,
+};
 
 void __init init_IRQ(void)
 {
-       int i;
+       int index;
 
-       for (i=0; i < XTENSA_NR_IRQS; i++)
-               irq_desc[i].chip = &xtensa_irq_type;
+       for (index = 0; index < XTENSA_NR_IRQS; index++) {
+               int mask = 1 << index;
 
-       cached_irq_mask = 0;
+               if (mask & XCHAL_INTTYPE_MASK_SOFTWARE)
+                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                                                handle_simple_irq);
 
-       platform_init_irq();
+               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE)
+                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                                                handle_edge_irq);
+
+               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL)
+                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                                                handle_level_irq);
+
+               else if (mask & XCHAL_INTTYPE_MASK_TIMER)
+                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                                                handle_edge_irq);
+
+               else    /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
+                       /* XCHAL_INTTYPE_MASK_NMI */
+
+                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                                                handle_level_irq);
+       }
+
+       cached_irq_mask = 0;
 }
index 6648fa9d9192908ce7dcdc046404e151a26d9018..ca76f071666e895aea125f3927d07bcb385fdcd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/xtensa/kernel/pci-dma.c
+ * arch/xtensa/pci-dma.c
  *
  * DMA coherent memory allocation.
  *
  */
 
 void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
 {
-       void *ret;
+       unsigned long ret;
+       unsigned long uncached = 0;
 
        /* ignore region speicifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
-       if (dev == NULL || (*dev->dma_mask < 0xffffffff))
-               gfp |= GFP_DMA;
-       ret = (void *)__get_free_pages(gfp, get_order(size));
+       flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
 
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *handle = virt_to_bus(ret);
+       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+               flag |= GFP_DMA;
+       ret = (unsigned long)__get_free_pages(flag, get_order(size));
+
+       if (ret == 0)
+               return NULL;
+
+       /* We currently don't support coherent memory outside KSEG */
+
+       if (ret < XCHAL_KSEG_CACHED_VADDR
+           || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE)
+               BUG();
+
+
+       if (ret != 0) {
+               memset((void*) ret, 0, size);
+               uncached = ret+XCHAL_KSEG_BYPASS_VADDR-XCHAL_KSEG_CACHED_VADDR;
+               *handle = virt_to_bus((void*)ret);
+               __flush_invalidate_dcache_range(ret, size);
        }
-       return (void*) BYPASS_ADDR((unsigned long)ret);
+
+       return (void*)uncached;
 }
 
 void dma_free_coherent(struct device *hwdev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
 {
-       free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size));
+       long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR;
+
+       if (addr < 0 || addr >= XCHAL_KSEG_SIZE)
+               BUG();
+
+       free_pages(addr, get_order(size));
 }
 
 
index a7c4178c2a8c2a126bc689a0408df9a5f92d3edf..795bd5ac6f4cf02f047a3971524685dd98224b33 100644 (file)
@@ -1,4 +1,3 @@
-// TODO        verify coprocessor handling
 /*
  * arch/xtensa/kernel/process.c
  *
@@ -43,7 +42,7 @@
 #include <asm/irq.h>
 #include <asm/atomic.h>
 #include <asm/asm-offsets.h>
-#include <asm/coprocessor.h>
+#include <asm/regs.h>
 
 extern void ret_from_fork(void);
 
@@ -67,25 +66,6 @@ void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
 
-#if XCHAL_CP_NUM > 0
-
-/*
- * Coprocessor ownership.
- */
-
-coprocessor_info_t coprocessor_info[] = {
-       { 0, XTENSA_CPE_CP0_OFFSET },
-       { 0, XTENSA_CPE_CP1_OFFSET },
-       { 0, XTENSA_CPE_CP2_OFFSET },
-       { 0, XTENSA_CPE_CP3_OFFSET },
-       { 0, XTENSA_CPE_CP4_OFFSET },
-       { 0, XTENSA_CPE_CP5_OFFSET },
-       { 0, XTENSA_CPE_CP6_OFFSET },
-       { 0, XTENSA_CPE_CP7_OFFSET },
-};
-
-#endif
-
 /*
  * Powermanagement idle function, if any is provided by the platform.
  */
@@ -110,12 +90,10 @@ void cpu_idle(void)
 
 void exit_thread(void)
 {
-       release_coprocessors(current);  /* Empty macro if no CPs are defined */
 }
 
 void flush_thread(void)
 {
-       release_coprocessors(current);  /* Empty macro if no CPs are defined */
 }
 
 /*
@@ -182,36 +160,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 }
 
 
-/*
- * Create a kernel thread
- */
-
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       long retval;
-       __asm__ __volatile__
-               ("mov           a5, %4\n\t" /* preserve fn in a5 */
-                "mov           a6, %3\n\t" /* preserve and setup arg in a6 */
-                "movi          a2, %1\n\t" /* load __NR_clone for syscall*/
-                "mov           a3, sp\n\t" /* sp check and sys_clone */
-                "mov           a4, %5\n\t" /* load flags for syscall */
-                "syscall\n\t"
-                "beq           a3, sp, 1f\n\t" /* branch if parent */
-                "callx4        a5\n\t"     /* call fn */
-                "movi          a2, %2\n\t" /* load __NR_exit for syscall */
-                "mov           a3, a6\n\t" /* load fn return value */
-                "syscall\n"
-                "1:\n\t"
-                "mov           %0, a2\n\t" /* parent returns zero */
-                :"=r" (retval)
-                :"i" (__NR_clone), "i" (__NR_exit),
-                "r" (arg), "r" (fn),
-                "r" (flags | CLONE_VM)
-                : "a2", "a3", "a4", "a5", "a6" );
-       return retval;
-}
-
-
 /*
  * These bracket the sleeping functions..
  */
@@ -275,7 +223,7 @@ void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
         */
 
        elfregs->pc             = regs->pc;
-       elfregs->ps             = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+       elfregs->ps             = (regs->ps & ~(1 << PS_EXCM_BIT));
        elfregs->exccause       = regs->exccause;
        elfregs->excvaddr       = regs->excvaddr;
        elfregs->windowbase     = regs->windowbase;
@@ -325,7 +273,7 @@ void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
         */
 
        regs->pc                = elfregs->pc;
-       regs->ps                = (elfregs->ps | XCHAL_PS_EXCM_MASK);
+       regs->ps                = (elfregs->ps | (1 << PS_EXCM_BIT));
        regs->exccause          = elfregs->exccause;
        regs->excvaddr          = elfregs->excvaddr;
        regs->windowbase        = elfregs->windowbase;
@@ -459,16 +407,7 @@ int  do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
 int
 dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
 {
-/* see asm/coprocessor.h for this magic number 16 */
-#if XTENSA_CP_EXTRA_SIZE > 16
-       do_save_fpregs (r, regs, task);
-
-       /*  For now, bit 16 means some extra state may be present:  */
-// FIXME!! need to track to return more accurate mask
-       return 0x10000 | XCHAL_CP_MASK;
-#else
        return 0;       /* no coprocessors active on this processor */
-#endif
 }
 
 /*
@@ -483,3 +422,44 @@ int  dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
 {
        return dump_task_fpu(regs, current, r);
 }
+
+asmlinkage
+long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
+                  void __user *parent_tid, void *child_tls,
+                  void __user *child_tid, long a5,
+                  struct pt_regs *regs)
+{
+        if (!newsp)
+                newsp = regs->areg[1];
+        return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
+}
+
+/*
+ *  * xtensa_execve() executes a new program.
+ *   */
+
+asmlinkage
+long xtensa_execve(char __user *name, char __user * __user *argv,
+                   char __user * __user *envp,
+                   long a3, long a4, long a5,
+                   struct pt_regs *regs)
+{
+       long error;
+       char * filename;
+
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+       // FIXME: release coprocessor??
+       error = do_execve(filename, argv, envp, regs);
+       if (error == 0) {
+               task_lock(current);
+               current->ptrace &= ~PT_DTRACE;
+               task_unlock(current);
+       }
+       putname(filename);
+out:
+       return error;
+}
+
index 9aea23cc0dc5aee76324d6c74b29bca72afe0e5d..8b6d3d0623b6f56d4570d9d866c33e38c8f65896 100644 (file)
@@ -96,7 +96,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        /* Note:  PS.EXCM is not set while user task is running;
                         * its being set in regs is for exception handling
                         * convenience.  */
-                       tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+                       tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
                        break;
                case REG_WB:
                        tmp = regs->windowbase;
@@ -332,12 +332,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 void do_syscall_trace(void)
 {
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-
-       if (!(current->ptrace & PT_PTRACED))
-               return;
-
        /*
         * The 0x80 provides a way for the tracing parent to distinguish
         * between a syscall stop and SIGTRAP delivery
@@ -354,3 +348,23 @@ void do_syscall_trace(void)
                current->exit_code = 0;
        }
 }
+
+void do_syscall_trace_enter(struct pt_regs *regs)
+{
+       if (test_thread_flag(TIF_SYSCALL_TRACE)
+                       && (current->ptrace & PT_PTRACED))
+               do_syscall_trace();
+
+#if 0
+       if (unlikely(current->audit_context))
+               audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
+#endif
+}
+
+void do_syscall_trace_leave(struct pt_regs *regs)
+{
+       if ((test_thread_flag(TIF_SYSCALL_TRACE))
+                       && (current->ptrace & PT_PTRACED))
+               do_syscall_trace();
+}
+
index c99ab72b41b6ee9e8d36bb5608435f45460ee74e..b6374c09de20e267b5235ae49968e1ca268d4a61 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/page.h>
 #include <asm/setup.h>
 
-#include <xtensa/config/system.h>
-
 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
 struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
 #endif
@@ -336,7 +334,7 @@ c_show(struct seq_file *f, void *slot)
        /* high-level stuff */
        seq_printf(f,"processor\t: 0\n"
                     "vendor_id\t: Tensilica\n"
-                    "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n"
+                    "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
                     "core ID\t\t: " XCHAL_CORE_ID "\n"
                     "build ID\t: 0x%x\n"
                     "byte order\t: %s\n"
@@ -420,25 +418,6 @@ c_show(struct seq_file *f, void *slot)
                     XCHAL_NUM_TIMERS,
                     XCHAL_DEBUGLEVEL);
 
-       /* Coprocessors */
-#if XCHAL_HAVE_CP
-       seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM);
-#else
-       seq_printf(f, "coprocessors\t: none\n");
-#endif
-
-       /* {I,D}{RAM,ROM} and XLMI */
-       seq_printf(f,"inst ROMs\t: %d\n"
-                    "inst RAMs\t: %d\n"
-                    "data ROMs\t: %d\n"
-                    "data RAMs\t: %d\n"
-                    "XLMI ports\t: %d\n",
-                    XCHAL_NUM_IROM,
-                    XCHAL_NUM_IRAM,
-                    XCHAL_NUM_DROM,
-                    XCHAL_NUM_DRAM,
-                    XCHAL_NUM_XLMI);
-
        /* Cache */
        seq_printf(f,"icache line size: %d\n"
                     "icache ways\t: %d\n"
@@ -466,24 +445,6 @@ c_show(struct seq_file *f, void *slot)
                     XCHAL_DCACHE_WAYS,
                     XCHAL_DCACHE_SIZE);
 
-       /* MMU */
-       seq_printf(f,"ASID bits\t: %d\n"
-                    "ASID invalid\t: %d\n"
-                    "ASID kernel\t: %d\n"
-                    "rings\t\t: %d\n"
-                    "itlb ways\t: %d\n"
-                    "itlb AR ways\t: %d\n"
-                    "dtlb ways\t: %d\n"
-                    "dtlb AR ways\t: %d\n",
-                    XCHAL_MMU_ASID_BITS,
-                    XCHAL_MMU_ASID_INVALID,
-                    XCHAL_MMU_ASID_KERNEL,
-                    XCHAL_MMU_RINGS,
-                    XCHAL_ITLB_WAYS,
-                    XCHAL_ITLB_ARF_WAYS,
-                    XCHAL_DTLB_WAYS,
-                    XCHAL_DTLB_ARF_WAYS);
-
        return 0;
 }
 
index c494f0826fc560f52258fd0a663d442b3d393ebd..c6d9880a4cdbf75fcd6c813a92b68ad9c2531d2d 100644 (file)
@@ -12,8 +12,8 @@
  *
  */
 
-#include <xtensa/config/core.h>
-#include <xtensa/hal.h>
+#include <asm/variant/core.h>
+#include <asm/coprocessor.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -46,7 +46,7 @@ extern struct task_struct *coproc_owners[];
  * Atomically swap in the new signal mask, and wait for a signal.
  */
 
-int sys_sigsuspend(struct pt_regs *regs)
+int xtensa_sigsuspend(struct pt_regs *regs)
 {
        old_sigset_t mask = (old_sigset_t) regs->areg[3];
        sigset_t saveset;
@@ -68,7 +68,7 @@ int sys_sigsuspend(struct pt_regs *regs)
 }
 
 asmlinkage int
-sys_rt_sigsuspend(struct pt_regs *regs)
+xtensa_rt_sigsuspend(struct pt_regs *regs)
 {
        sigset_t *unewset = (sigset_t *) regs->areg[4];
        size_t sigsetsize = (size_t) regs->areg[3];
@@ -96,7 +96,7 @@ sys_rt_sigsuspend(struct pt_regs *regs)
 }
 
 asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
+xtensa_sigaction(int sig, const struct old_sigaction *act,
              struct old_sigaction *oact)
 {
        struct k_sigaction new_ka, old_ka;
@@ -128,7 +128,7 @@ sys_sigaction(int sig, const struct old_sigaction *act,
 }
 
 asmlinkage int
-sys_sigaltstack(struct pt_regs *regs)
+xtensa_sigaltstack(struct pt_regs *regs)
 {
        const stack_t *uss = (stack_t *) regs->areg[4];
        stack_t *uoss = (stack_t *) regs->areg[3];
@@ -216,8 +216,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
         * handler, or the user mode value doesn't matter (e.g. PS.OWB).
         */
        err |= __get_user(ps, &sc->sc_ps);
-       regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK)
-               | (ps & XCHAL_PS_CALLINC_MASK);
+       regs->ps = (regs->ps & ~PS_CALLINC_MASK)
+               | (ps & PS_CALLINC_MASK);
 
        /* Additional corruption checks */
 
@@ -280,7 +280,7 @@ flush_my_cpstate(struct task_struct *tsk)
 static int
 save_cpextra (struct _cpstate *buf)
 {
-#if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
+#if XCHAL_CP_NUM == 0
        return 0;
 #else
 
@@ -350,7 +350,7 @@ setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
        return err;
 }
 
-asmlinkage int sys_sigreturn(struct pt_regs *regs)
+asmlinkage int xtensa_sigreturn(struct pt_regs *regs)
 {
        struct sigframe *frame = (struct sigframe *)regs->areg[1];
        sigset_t set;
@@ -382,7 +382,7 @@ badframe:
        return 0;
 }
 
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
        sigset_t set;
@@ -497,8 +497,10 @@ gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn)
 
        /* Flush generated code out of the data cache */
 
-       if (err == 0)
-               __flush_invalidate_cache_range((unsigned long)codemem, 6UL);
+       if (err == 0) {
+               __invalidate_icache_range((unsigned long)codemem, 6UL);
+               __flush_invalidate_dcache_range((unsigned long)codemem, 6UL);
+       }
 
        return err;
 }
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
new file mode 100644 (file)
index 0000000..418268f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/xtensa/kernel/syscall.c
+ *
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+#include <asm/uaccess.h>
+#include <asm/syscalls.h>
+#include <asm/unistd.h>
+#include <linux/linkage.h>
+#include <linux/stringify.h>
+#include <linux/errno.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include <linux/shm.h>
+
+typedef void (*syscall_t)(void);
+
+syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
+       [0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall,
+
+#undef __SYSCALL
+#define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol,
+#undef _XTENSA_UNISTD_H
+#undef  __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+};
+
+/*
+ * xtensa_pipe() is the normal C calling standard for creating a pipe. It's not
+ * the way unix traditional does this, though.
+ */
+
+asmlinkage long xtensa_pipe(int __user *userfds)
+{
+       int fd[2];
+       int error;
+
+       error = do_pipe(fd);
+       if (!error) {
+               if (copy_to_user(userfds, fd, 2 * sizeof(int)))
+                       error = -EFAULT;
+       }
+       return error;
+}
+
+
+asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len,
+                            unsigned long prot, unsigned long flags,
+                            unsigned long fd, unsigned long pgoff)
+{
+       int error = -EBADF;
+       struct file * file = NULL;
+
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+       if (!(flags & MAP_ANONYMOUS)) {
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
+       down_write(&current->mm->mmap_sem);
+       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
+       if (file)
+               fput(file);
+out:
+       return error;
+}
+
+asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
+{
+       unsigned long ret;
+       long err;
+
+       err = do_shmat(shmid, shmaddr, shmflg, &ret);
+       if (err)
+               return err;
+       return (long)ret;
+}
+
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
deleted file mode 100644 (file)
index f49cb23..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * arch/xtensa/kernel/syscalls.c
- *
- * 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.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- * Copyright (C) 2000 Silicon Graphics, Inc.
- * Copyright (C) 1995 - 2000 by Ralf Baechle
- *
- * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
- * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
- * Chris Zankel <chris@zankel.net>
- * Kevin Chea
- *
- */
-
-#define DEBUG  0
-
-#include <linux/linkage.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/mman.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/utsname.h>
-#include <linux/unistd.h>
-#include <linux/stringify.h>
-#include <linux/syscalls.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/errno.h>
-#include <asm/ptrace.h>
-#include <asm/signal.h>
-#include <asm/uaccess.h>
-#include <asm/hardirq.h>
-#include <asm/mman.h>
-#include <asm/shmparam.h>
-#include <asm/page.h>
-
-extern void do_syscall_trace(void);
-typedef int (*syscall_t)(void *a0,...);
-extern syscall_t sys_call_table[];
-extern unsigned char sys_narg_table[];
-
-/*
- * sys_pipe() is the normal C calling standard for creating a pipe. It's not
- * the way unix traditional does this, though.
- */
-
-int sys_pipe(int __user *userfds)
-{
-       int fd[2];
-       int error;
-
-       error = do_pipe(fd);
-       if (!error) {
-               if (copy_to_user(userfds, fd, 2 * sizeof(int)))
-                       error = -EFAULT;
-       }
-       return error;
-}
-
-/*
- * Common code for old and new mmaps.
- */
-long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot,
-             unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
-       int error = -EBADF;
-       struct file * file = NULL;
-
-       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
-                       goto out;
-       }
-
-       down_write(&current->mm->mmap_sem);
-       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-       up_write(&current->mm->mmap_sem);
-
-       if (file)
-               fput(file);
-out:
-       return error;
-}
-
-int sys_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-       int __user *parent_tidptr, *child_tidptr;
-       clone_flags = regs->areg[4];
-       newsp = regs->areg[3];
-       parent_tidptr = (int __user *)regs->areg[5];
-       child_tidptr = (int __user *)regs->areg[6];
-       if (!newsp)
-               newsp = regs->areg[1];
-       return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-
-int sys_execve(struct pt_regs *regs)
-{
-       int error;
-       char * filename;
-
-       filename = getname((char *) (long)regs->areg[5]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename, (char **) (long)regs->areg[3],
-                         (char **) (long)regs->areg[4], regs);
-       putname(filename);
-
-out:
-       return error;
-}
-
-int sys_uname(struct old_utsname * name)
-{
-       if (name && !copy_to_user(name, utsname(), sizeof (*name)))
-               return 0;
-       return -EFAULT;
-}
-
-/*
- * Build the string table for the builtin "poor man's strace".
- */
-
-#if DEBUG
-#define SYSCALL(fun, narg) #fun,
-static char *sfnames[] = {
-#include "syscalls.h"
-};
-#undef SYS
-#endif
-
-void system_call (struct pt_regs *regs)
-{
-       syscall_t syscall;
-       unsigned long parm0, parm1, parm2, parm3, parm4, parm5;
-       int nargs, res;
-       unsigned int syscallnr;
-       int ps;
-
-#if DEBUG
-       int i;
-       unsigned long parms[6];
-       char *sysname;
-#endif
-
-       regs->syscall = regs->areg[2];
-
-       do_syscall_trace();
-
-       /* Have to load after syscall_trace because strace
-        * sometimes changes regs->syscall.
-        */
-       syscallnr = regs->syscall;
-
-       parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0;
-
-       /* Restore interrupt level to syscall invoker's.
-        * If this were in assembly, we wouldn't disable
-        * interrupts in the first place:
-        */
-       local_save_flags (ps);
-       local_irq_restore((ps & ~XCHAL_PS_INTLEVEL_MASK) |
-                         (regs->ps & XCHAL_PS_INTLEVEL_MASK) );
-
-       if (syscallnr > __NR_Linux_syscalls) {
-               regs->areg[2] = -ENOSYS;
-               return;
-       }
-
-       syscall = sys_call_table[syscallnr];
-       nargs = sys_narg_table[syscallnr];
-
-       if (syscall == NULL) {
-               regs->areg[2] = -ENOSYS;
-               return;
-       }
-
-       /* There shouldn't be more than six arguments in the table! */
-
-       if (nargs > 6)
-               panic("Internal error - too many syscall arguments (%d)!\n",
-                     nargs);
-
-       /* Linux takes system-call arguments in registers.  The ABI
-         * and Xtensa software conventions require the system-call
-         * number in a2.  If an argument exists in a2, we move it to
-         * the next available register.  Note that for improved
-         * efficiency, we do NOT shift all parameters down one
-         * register to maintain the original order.
-        *
-         * At best case (zero arguments), we just write the syscall
-         * number to a2.  At worst case (1 to 6 arguments), we move
-         * the argument in a2 to the next available register, then
-         * write the syscall number to a2.
-        *
-         * For clarity, the following truth table enumerates all
-         * possibilities.
-        *
-         * arguments   syscall number  arg0, arg1, arg2, arg3, arg4, arg5
-         * ---------   --------------  ----------------------------------
-        *      0             a2
-        *      1             a2        a3
-        *      2             a2        a4,   a3
-        *      3             a2        a5,   a3,   a4
-        *      4             a2        a6,   a3,   a4,   a5
-        *      5             a2        a7,   a3,   a4,   a5,   a6
-        *      6             a2        a8,   a3,   a4,   a5,   a6,   a7
-        */
-       if (nargs) {
-               parm0 = regs->areg[nargs+2];
-               parm1 = regs->areg[3];
-               parm2 = regs->areg[4];
-               parm3 = regs->areg[5];
-               parm4 = regs->areg[6];
-               parm5 = regs->areg[7];
-       } else /* nargs == 0 */
-               parm0 = (unsigned long) regs;
-
-#if DEBUG
-       parms[0] = parm0;
-       parms[1] = parm1;
-       parms[2] = parm2;
-       parms[3] = parm3;
-       parms[4] = parm4;
-       parms[5] = parm5;
-
-       sysname = sfnames[syscallnr];
-       if (strncmp(sysname, "sys_", 4) == 0)
-               sysname = sysname + 4;
-
-       printk("\017SYSCALL:I:%x:%d:%s  %s(", regs->pc, current->pid,
-              current->comm, sysname);
-       for (i = 0; i < nargs; i++)
-               printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
-       printk(")\n");
-#endif
-
-       res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5);
-
-#if DEBUG
-       printk("\017SYSCALL:O:%d:%s  %s(",current->pid, current->comm, sysname);
-       for (i = 0; i < nargs; i++)
-               printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
-       if (res < 4096)
-               printk(") = %d\n", res);
-       else
-               printk(") = %#x\n", res);
-#endif /* DEBUG */
-
-       regs->areg[2] = res;
-       do_syscall_trace();
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
-{
-       long __res;
-       asm volatile (
-               "  mov   a5, %2 \n"
-               "  mov   a4, %4 \n"
-               "  mov   a3, %3 \n"
-               "  movi  a2, %1 \n"
-               "  syscall      \n"
-               "  mov   %0, a2 \n"
-               : "=a" (__res)
-               : "i" (__NR_execve), "a" (filename), "a" (argv), "a" (envp)
-               : "a2", "a3", "a4", "a5");
-       return __res;
-}
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
deleted file mode 100644 (file)
index 216c10a..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * arch/xtensa/kernel/syscalls.h
- *
- * 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.
- *
- * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- *
- * Changes by Joe Taylor <joe@tensilica.com>
- */
-
-/*
- * This file is being included twice - once to build a list of all
- * syscalls and once to build a table of how many arguments each syscall
- * accepts.  Syscalls that receive a pointer to the saved registers are
- * marked as having zero arguments.
- *
- * The binary compatibility calls are in a separate list.
- *
- * Entry '0' used to be system_call.  It's removed to disable indirect
- * system calls for now so user tasks can't recurse.  See mips'
- * sys_syscall for a comparable example.
- */
-
-SYSCALL(0, 0)                          /* 00 */
-SYSCALL(sys_exit, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_read, 3)
-SYSCALL(sys_write, 3)
-SYSCALL(sys_open, 3)                   /* 05 */
-SYSCALL(sys_close, 1)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_creat, 2)
-SYSCALL(sys_link, 2)
-SYSCALL(sys_unlink, 1)                 /* 10 */
-SYSCALL(sys_execve, 0)
-SYSCALL(sys_chdir, 1)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_mknod, 3)
-SYSCALL(sys_chmod, 2)                  /* 15 */
-SYSCALL(sys_lchown, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_newstat, 2)
-SYSCALL(sys_lseek, 3)
-SYSCALL(sys_getpid, 0)                 /* 20 */
-SYSCALL(sys_mount, 5)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_setuid, 1)
-SYSCALL(sys_getuid, 0)
-SYSCALL(sys_ni_syscall, 1)             /* 25 */
-SYSCALL(sys_ptrace, 4)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_newfstat, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_utime, 2)                  /* 30 */
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_access, 2)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_ni_syscall, 0)             /* 35 */
-SYSCALL(sys_sync, 0)
-SYSCALL(sys_kill, 2)
-SYSCALL(sys_rename, 2)
-SYSCALL(sys_mkdir, 2)
-SYSCALL(sys_rmdir, 1)                  /* 40 */
-SYSCALL(sys_dup, 1)
-SYSCALL(sys_pipe, 1)
-SYSCALL(sys_times, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_brk, 1)                    /* 45 */
-SYSCALL(sys_setgid, 1)
-SYSCALL(sys_getgid, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_geteuid, 0)
-SYSCALL(sys_getegid, 0)                        /* 50 */
-SYSCALL(sys_acct, 1)
-SYSCALL(sys_umount, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ioctl, 3)
-SYSCALL(sys_fcntl, 3)                  /* 55 */
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_setpgid, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_umask, 1)                  /* 60 */
-SYSCALL(sys_chroot, 1)
-SYSCALL(sys_ustat, 2)
-SYSCALL(sys_dup2, 2)
-SYSCALL(sys_getppid, 0)
-SYSCALL(sys_ni_syscall, 0)             /* 65 */
-SYSCALL(sys_setsid, 0)
-SYSCALL(sys_sigaction, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_setreuid, 2)               /* 70 */
-SYSCALL(sys_setregid, 2)
-SYSCALL(sys_sigsuspend, 0)
-SYSCALL(sys_ni_syscall, 1)
-SYSCALL(sys_sethostname, 2)
-SYSCALL(sys_setrlimit, 2)              /* 75 */
-SYSCALL(sys_getrlimit, 2)
-SYSCALL(sys_getrusage, 2)
-SYSCALL(sys_gettimeofday, 2)
-SYSCALL(sys_settimeofday, 2)
-SYSCALL(sys_getgroups, 2)              /* 80 */
-SYSCALL(sys_setgroups, 2)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_symlink, 2)
-SYSCALL(sys_newlstat, 2)
-SYSCALL(sys_readlink, 3)               /* 85 */
-SYSCALL(sys_uselib, 1)
-SYSCALL(sys_swapon, 2)
-SYSCALL(sys_reboot, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 6)             /* 90 */
-SYSCALL(sys_munmap, 2)
-SYSCALL(sys_truncate, 2)
-SYSCALL(sys_ftruncate, 2)
-SYSCALL(sys_fchmod, 2)
-SYSCALL(sys_fchown, 3)                 /* 95 */
-SYSCALL(sys_getpriority, 2)
-SYSCALL(sys_setpriority, 3)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_statfs, 2)
-SYSCALL(sys_fstatfs, 2)                        /* 100 */
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_syslog, 3)
-SYSCALL(sys_setitimer, 3)
-SYSCALL(sys_getitimer, 2)              /* 105 */
-SYSCALL(sys_newstat, 2)
-SYSCALL(sys_newlstat, 2)
-SYSCALL(sys_newfstat, 2)
-SYSCALL(sys_uname, 1)
-SYSCALL(sys_ni_syscall, 0)             /* 110 */
-SYSCALL(sys_vhangup, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_wait4, 4)
-SYSCALL(sys_swapoff, 1)                        /* 115 */
-SYSCALL(sys_sysinfo, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_fsync, 1)
-SYSCALL(sys_sigreturn, 0)
-SYSCALL(sys_clone, 0)                  /* 120 */
-SYSCALL(sys_setdomainname, 2)
-SYSCALL(sys_newuname, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_adjtimex, 1)
-SYSCALL(sys_mprotect, 3)               /* 125 */
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 2)
-SYSCALL(sys_init_module, 2)
-SYSCALL(sys_delete_module, 1)
-SYSCALL(sys_ni_syscall, 1)             /* 130 */
-SYSCALL(sys_quotactl, 0)
-SYSCALL(sys_getpgid, 1)
-SYSCALL(sys_fchdir, 1)
-SYSCALL(sys_bdflush, 2)
-SYSCALL(sys_sysfs, 3)                  /* 135 */
-SYSCALL(sys_personality, 1)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_setfsuid, 1)
-SYSCALL(sys_setfsgid, 1)
-SYSCALL(sys_llseek, 5)                 /* 140 */
-SYSCALL(sys_getdents, 3)
-SYSCALL(sys_select, 5)
-SYSCALL(sys_flock, 2)
-SYSCALL(sys_msync, 3)
-SYSCALL(sys_readv, 3)                  /* 145 */
-SYSCALL(sys_writev, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 3)
-SYSCALL(sys_ni_syscall, 4)             /* handled in fast syscall handler. */
-SYSCALL(sys_ni_syscall, 0)             /* 150 */
-SYSCALL(sys_getsid, 1)
-SYSCALL(sys_fdatasync, 1)
-SYSCALL(sys_sysctl, 1)
-SYSCALL(sys_mlock, 2)
-SYSCALL(sys_munlock, 2)                        /* 155 */
-SYSCALL(sys_mlockall, 1)
-SYSCALL(sys_munlockall, 0)
-SYSCALL(sys_sched_setparam,2)
-SYSCALL(sys_sched_getparam,2)
-SYSCALL(sys_sched_setscheduler,3)      /* 160 */
-SYSCALL(sys_sched_getscheduler,1)
-SYSCALL(sys_sched_yield,0)
-SYSCALL(sys_sched_get_priority_max,1)
-SYSCALL(sys_sched_get_priority_min,1)
-SYSCALL(sys_sched_rr_get_interval,2)   /* 165 */
-SYSCALL(sys_nanosleep,2)
-SYSCALL(sys_mremap,4)
-SYSCALL(sys_accept, 3)
-SYSCALL(sys_bind, 3)
-SYSCALL(sys_connect, 3)                        /* 170 */
-SYSCALL(sys_getpeername, 3)
-SYSCALL(sys_getsockname, 3)
-SYSCALL(sys_getsockopt, 5)
-SYSCALL(sys_listen, 2)
-SYSCALL(sys_recv, 4)                   /* 175 */
-SYSCALL(sys_recvfrom, 6)
-SYSCALL(sys_recvmsg, 3)
-SYSCALL(sys_send, 4)
-SYSCALL(sys_sendmsg, 3)
-SYSCALL(sys_sendto, 6)                 /* 180 */
-SYSCALL(sys_setsockopt, 5)
-SYSCALL(sys_shutdown, 2)
-SYSCALL(sys_socket, 3)
-SYSCALL(sys_socketpair, 4)
-SYSCALL(sys_setresuid, 3)              /* 185 */
-SYSCALL(sys_getresuid, 3)
-SYSCALL(sys_ni_syscall, 5)
-SYSCALL(sys_poll, 3)
-SYSCALL(sys_nfsservctl, 3)
-SYSCALL(sys_setresgid, 3)              /* 190 */
-SYSCALL(sys_getresgid, 3)
-SYSCALL(sys_prctl, 5)
-SYSCALL(sys_rt_sigreturn, 0)
-SYSCALL(sys_rt_sigaction, 4)
-SYSCALL(sys_rt_sigprocmask, 4)         /* 195 */
-SYSCALL(sys_rt_sigpending, 2)
-SYSCALL(sys_rt_sigtimedwait, 4)
-SYSCALL(sys_rt_sigqueueinfo, 3)
-SYSCALL(sys_rt_sigsuspend, 0)
-SYSCALL(sys_pread64, 5)                        /* 200 */
-SYSCALL(sys_pwrite64, 5)
-SYSCALL(sys_chown, 3)
-SYSCALL(sys_getcwd, 2)
-SYSCALL(sys_capget, 2)
-SYSCALL(sys_capset, 2)                 /* 205 */
-SYSCALL(sys_sigaltstack, 0)
-SYSCALL(sys_sendfile, 4)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_ni_syscall, 0)
-SYSCALL(sys_mmap, 6)                   /* 210 */
-SYSCALL(sys_truncate64, 2)
-SYSCALL(sys_ftruncate64, 2)
-SYSCALL(sys_stat64, 2)
-SYSCALL(sys_lstat64, 2)
-SYSCALL(sys_fstat64, 2)                        /* 215 */
-SYSCALL(sys_pivot_root, 2)
-SYSCALL(sys_mincore, 3)
-SYSCALL(sys_madvise, 3)
-SYSCALL(sys_getdents64, 3)
-SYSCALL(sys_ni_syscall, 0)             /* 220 */
index 37347e36998723aaaf7803a3185cf9543cd9f805..a350431363a0a8c56080c170ab5a7ff88db2c50d 100644 (file)
@@ -47,7 +47,7 @@ unsigned long long sched_clock(void)
        return (unsigned long long)jiffies * (1000000000 / HZ);
 }
 
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t timer_interrupt(int irq, void *dev_id);
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
        .flags =        IRQF_DISABLED,
@@ -150,7 +150,7 @@ EXPORT_SYMBOL(do_gettimeofday);
  * The timer interrupt is called HZ times per second.
  */
 
-irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t timer_interrupt (int irq, void *dev_id)
 {
 
        unsigned long next;
@@ -160,9 +160,9 @@ irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 again:
        while ((signed long)(get_ccount() - next) > 0) {
 
-               profile_tick(CPU_PROFILING, regs);
+               profile_tick(CPU_PROFILING);
 #ifndef CONFIG_SMP
-               update_process_times(user_mode(regs));
+               update_process_times(user_mode(get_irq_regs()));
 #endif
 
                write_seqlock(&xtime_lock);
index ce077d6bf3a02eff9c9d59165d60a7b43a521044..693ab268485eaeee04b3a537298e1760bcf74bed 100644 (file)
@@ -75,7 +75,7 @@ extern void system_call (struct pt_regs*);
 #define USER           0x02
 
 #define COPROCESSOR(x)                                                 \
-{ XCHAL_EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
+{ EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
 
 typedef struct {
        int cause;
@@ -85,38 +85,38 @@ typedef struct {
 
 dispatch_init_table_t __init dispatch_init_table[] = {
 
-{ XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION,  0,         do_illegal_instruction},
-{ XCHAL_EXCCAUSE_SYSTEM_CALL,          KRNL,      fast_syscall_kernel },
-{ XCHAL_EXCCAUSE_SYSTEM_CALL,          USER,      fast_syscall_user },
-{ XCHAL_EXCCAUSE_SYSTEM_CALL,          0,         system_call },
-/* XCHAL_EXCCAUSE_INSTRUCTION_FETCH unhandled */
-/* XCHAL_EXCCAUSE_LOAD_STORE_ERROR unhandled*/
-{ XCHAL_EXCCAUSE_LEVEL1_INTERRUPT,     0,         do_interrupt },
-{ XCHAL_EXCCAUSE_ALLOCA,               USER|KRNL, fast_alloca },
-/* XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
-/* XCHAL_EXCCAUSE_PRIVILEGED unhandled */
+{ EXCCAUSE_ILLEGAL_INSTRUCTION,        0,         do_illegal_instruction},
+{ EXCCAUSE_SYSTEM_CALL,                KRNL,      fast_syscall_kernel },
+{ EXCCAUSE_SYSTEM_CALL,                USER,      fast_syscall_user },
+{ EXCCAUSE_SYSTEM_CALL,                0,         system_call },
+/* EXCCAUSE_INSTRUCTION_FETCH unhandled */
+/* EXCCAUSE_LOAD_STORE_ERROR unhandled*/
+{ EXCCAUSE_LEVEL1_INTERRUPT,   0,         do_interrupt },
+{ EXCCAUSE_ALLOCA,             USER|KRNL, fast_alloca },
+/* EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
+/* EXCCAUSE_PRIVILEGED unhandled */
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
 #ifdef CONFIG_UNALIGNED_USER
-{ XCHAL_EXCCAUSE_UNALIGNED,            USER,      fast_unaligned },
+{ EXCCAUSE_UNALIGNED,          USER,      fast_unaligned },
 #else
-{ XCHAL_EXCCAUSE_UNALIGNED,            0,         do_unaligned_user },
+{ EXCCAUSE_UNALIGNED,          0,         do_unaligned_user },
 #endif
-{ XCHAL_EXCCAUSE_UNALIGNED,            KRNL,      fast_unaligned },
+{ EXCCAUSE_UNALIGNED,          KRNL,      fast_unaligned },
 #endif
-{ XCHAL_EXCCAUSE_ITLB_MISS,            0,         do_page_fault },
-{ XCHAL_EXCCAUSE_ITLB_MISS,            USER|KRNL, fast_second_level_miss},
-{ XCHAL_EXCCAUSE_ITLB_MULTIHIT,                0,         do_multihit },
-{ XCHAL_EXCCAUSE_ITLB_PRIVILEGE,       0,         do_page_fault },
-/* XCHAL_EXCCAUSE_SIZE_RESTRICTION unhandled */
-{ XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE,        0,         do_page_fault },
-{ XCHAL_EXCCAUSE_DTLB_MISS,            USER|KRNL, fast_second_level_miss},
-{ XCHAL_EXCCAUSE_DTLB_MISS,            0,         do_page_fault },
-{ XCHAL_EXCCAUSE_DTLB_MULTIHIT,                0,         do_multihit },
-{ XCHAL_EXCCAUSE_DTLB_PRIVILEGE,       0,         do_page_fault },
-/* XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
-{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,        USER|KRNL, fast_store_prohibited },
-{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,        0,         do_page_fault },
-{ XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0,         do_page_fault },
+{ EXCCAUSE_ITLB_MISS,          0,         do_page_fault },
+{ EXCCAUSE_ITLB_MISS,          USER|KRNL, fast_second_level_miss},
+{ EXCCAUSE_ITLB_MULTIHIT,              0,         do_multihit },
+{ EXCCAUSE_ITLB_PRIVILEGE,     0,         do_page_fault },
+/* EXCCAUSE_SIZE_RESTRICTION unhandled */
+{ EXCCAUSE_FETCH_CACHE_ATTRIBUTE,      0,         do_page_fault },
+{ EXCCAUSE_DTLB_MISS,          USER|KRNL, fast_second_level_miss},
+{ EXCCAUSE_DTLB_MISS,          0,         do_page_fault },
+{ EXCCAUSE_DTLB_MULTIHIT,              0,         do_multihit },
+{ EXCCAUSE_DTLB_PRIVILEGE,     0,         do_page_fault },
+/* EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
+{ EXCCAUSE_STORE_CACHE_ATTRIBUTE,      USER|KRNL, fast_store_prohibited },
+{ EXCCAUSE_STORE_CACHE_ATTRIBUTE,      0,         do_page_fault },
+{ EXCCAUSE_LOAD_CACHE_ATTRIBUTE,       0,         do_page_fault },
 /* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
 #if (XCHAL_CP_MASK & 1)
 COPROCESSOR(0),
index 0e74397bfa2bd8168660ca29c7ae439cd23fcee8..eb2d7bb69ee071352ef9124efb75b7a743d27649 100644 (file)
@@ -53,6 +53,8 @@
 #include <asm/thread_info.h>
 #include <asm/processor.h>
 
+#define WINDOW_VECTORS_SIZE   0x180
+
 
 /*
  * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
@@ -210,7 +212,7 @@ ENTRY(_DoubleExceptionVector)
        /* Check for kernel double exception (usually fatal). */
 
        rsr     a3, PS
-       _bbci.l a3, PS_UM_SHIFT, .Lksp
+       _bbci.l a3, PS_UM_BIT, .Lksp
 
        /* Check if we are currently handling a window exception. */
        /* Note: We don't need to indicate that we enter a critical section. */
@@ -219,7 +221,7 @@ ENTRY(_DoubleExceptionVector)
 
        movi    a3, XCHAL_WINDOW_VECTORS_VADDR
        _bltu   a0, a3, .Lfixup
-       addi    a3, a3, XSHAL_WINDOW_VECTORS_SIZE
+       addi    a3, a3, WINDOW_VECTORS_SIZE
        _bgeu   a0, a3, .Lfixup
 
        /* Window overflow/underflow exception. Get stack pointer. */
@@ -245,7 +247,7 @@ ENTRY(_DoubleExceptionVector)
 
        wsr     a2, DEPC                # save stack pointer temporarily
        rsr     a0, PS
-       extui   a0, a0, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+       extui   a0, a0, PS_OWB_SHIFT, 4
        wsr     a0, WINDOWBASE
        rsync
 
@@ -312,8 +314,8 @@ ENTRY(_DoubleExceptionVector)
 .Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
 
        rsr     a3, EXCCAUSE
-       beqi    a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f
-       addi    a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS
+       beqi    a3, EXCCAUSE_ITLB_MISS, 1f
+       addi    a3, a3, -EXCCAUSE_DTLB_MISS
        bnez    a3, .Lunrecoverable
 1:     movi    a3, fast_second_level_miss_double_kernel
        jx      a3
index cfe75f52872593f9bdefa8c7871421e4bc89848b..a36c104c3a5295a05e89a0ef1eaf1c0d27b8cfd1 100644 (file)
 
 #include <asm-generic/vmlinux.lds.h>
 
-#define _NOCLANGUAGE
-#include <xtensa/config/core.h>
-#include <xtensa/config/system.h>
+#include <asm/variant/core.h>
 OUTPUT_ARCH(xtensa)
 ENTRY(_start)
 
-#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
+#ifdef __XTENSA_EB__
 jiffies = jiffies_64 + 4;
 #else
 jiffies = jiffies_64;
 #endif
 
-#define KERNELOFFSET 0x1000
+#define KERNELOFFSET 0xd0001000
 
 /* Note: In the following macros, it would be nice to specify only the
    vector name and section kind and construct "sym" and "section" using
@@ -75,7 +73,7 @@ jiffies = jiffies_64;
 
 SECTIONS
 {
-  . = XCHAL_KSEG_CACHED_VADDR + KERNELOFFSET;
+  . = KERNELOFFSET;
   /* .text section */
 
   _text = .;
@@ -159,7 +157,7 @@ SECTIONS
 
   /* Initialization code and data: */
 
-  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+  . = ALIGN(1 << 12);
   __init_begin = .;
   .init.text : {
        _sinittext = .;
@@ -223,32 +221,32 @@ SECTIONS
                  .dummy)
   SECTION_VECTOR (_DebugInterruptVector_literal,
                  .DebugInterruptVector.literal,
-                 XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) - 4,
+                 XCHAL_DEBUG_VECTOR_VADDR - 4,
                  SIZEOF(.WindowVectors.text),
                  .WindowVectors.text)
   SECTION_VECTOR (_DebugInterruptVector_text,
                  .DebugInterruptVector.text,
-                 XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL),
+                 XCHAL_DEBUG_VECTOR_VADDR,
                  4,
                  .DebugInterruptVector.literal)
   SECTION_VECTOR (_KernelExceptionVector_literal,
                  .KernelExceptionVector.literal,
-                 XCHAL_KERNELEXC_VECTOR_VADDR - 4,
+                 XCHAL_KERNEL_VECTOR_VADDR - 4,
                  SIZEOF(.DebugInterruptVector.text),
                  .DebugInterruptVector.text)
   SECTION_VECTOR (_KernelExceptionVector_text,
                  .KernelExceptionVector.text,
-                 XCHAL_KERNELEXC_VECTOR_VADDR,
+                 XCHAL_KERNEL_VECTOR_VADDR,
                  4,
                  .KernelExceptionVector.literal)
   SECTION_VECTOR (_UserExceptionVector_literal,
                  .UserExceptionVector.literal,
-                 XCHAL_USEREXC_VECTOR_VADDR - 4,
+                 XCHAL_USER_VECTOR_VADDR - 4,
                  SIZEOF(.KernelExceptionVector.text),
                  .KernelExceptionVector.text)
   SECTION_VECTOR (_UserExceptionVector_text,
                  .UserExceptionVector.text,
-                 XCHAL_USEREXC_VECTOR_VADDR,
+                 XCHAL_USER_VECTOR_VADDR,
                  4,
                  .UserExceptionVector.literal)
   SECTION_VECTOR (_DoubleExceptionVector_literal,
@@ -263,7 +261,7 @@ SECTIONS
                  .DoubleExceptionVector.literal)
 
   . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
-  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+  . = ALIGN(1 << 12);
 
   __init_end = .;
 
index e2d64dfd530cc47296a36c9a950711aa6af6abac..9d9cd990afa6ab0e40e46858cdb9d29977c4ec2c 100644 (file)
@@ -16,8 +16,7 @@
 
 #include <asm/errno.h>
 #include <linux/linkage.h>
-#define _ASMLANGUAGE
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
index e8f6d7eb72222d20e9f095c1d6f36a8db378fe50..ddda8f4bc86266d22daec784bd3ff93bb8857bdf 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright (C) 2002 - 2005 Tensilica Inc.
  */
 
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
 
        .macro  src_b   r, w0, w1
 #ifdef __XTENSA_EB__
index 4de25134bc62aa2f4ce939175e0e0eee4f278201..56a17495b2db3134c02f224c41b2c7d850e7a21d 100644 (file)
@@ -11,7 +11,7 @@
  *  Copyright (C) 2002 Tensilica Inc.
  */
 
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
 
 /*
  * void *memset(void *dst, int c, size_t length)
index 71d55df43893e7033ea8e6080c7a2df2c2328eba..a834057bda6b45040a6182705e9610fb1448377e 100644 (file)
@@ -11,7 +11,7 @@
  *  Copyright (C) 2002 Tensilica Inc.
  */
 
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
 #include <linux/errno.h>
 
 /* Load or store instructions that may cause exceptions use the EX macro. */
index cdff4d670f3bf2ee5ce43040b8dcbcadbb4d3056..5e9c1e709b2eaf33d32d883a4681453398027313 100644 (file)
@@ -11,7 +11,7 @@
  *  Copyright (C) 2002 Tensilica Inc.
  */
 
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
 
 /* Load or store instructions that may cause exceptions use the EX macro. */
 
index 4641ef510f0e0a269dbc082e68102c70c7c0162b..a8ab1d4fe0ae1530026d1cfe6542071c7387cf81 100644 (file)
@@ -53,7 +53,7 @@
  *     a11/ original length
  */
 
-#include <xtensa/coreasm.h>
+#include <asm/variant/core.h>
 
 #ifdef __XTENSA_EB__
 #define ALIGN(R, W0, W1) src   R, W0, W1
index dd0dbec2e57e4f39b51ab7a73359a0117e638b48..3dc6f2f07bbe07a7737cda1077b3fc253a4107e0 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/system.h>
 #include <asm/pgalloc.h>
 
-unsigned long asid_cache = ASID_FIRST_VERSION;
+unsigned long asid_cache = ASID_USER_FIRST;
 void bad_page_fault(struct pt_regs*, unsigned long, int);
 
 /*
@@ -58,10 +58,10 @@ void do_page_fault(struct pt_regs *regs)
                return;
        }
 
-       is_write = (exccause == XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
-       is_exec =  (exccause == XCHAL_EXCCAUSE_ITLB_PRIVILEGE ||
-                   exccause == XCHAL_EXCCAUSE_ITLB_MISS ||
-                   exccause == XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
+       is_write = (exccause == EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
+       is_exec =  (exccause == EXCCAUSE_ITLB_PRIVILEGE ||
+                   exccause == EXCCAUSE_ITLB_MISS ||
+                   exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
 
 #if 0
        printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
index 660ef058c14944d133abff3ac49e663445367b42..e1ec2d1e8189e64c998ba8dba7d9b3a9d30d5cc1 100644 (file)
@@ -141,8 +141,8 @@ void __init bootmem_init(void)
        if (min_low_pfn > max_pfn)
                panic("No memory found!\n");
 
-       max_low_pfn = max_pfn < MAX_LOW_MEMORY >> PAGE_SHIFT ?
-               max_pfn : MAX_LOW_MEMORY >> PAGE_SHIFT;
+       max_low_pfn = max_pfn < MAX_MEM_PFN >> PAGE_SHIFT ?
+               max_pfn : MAX_MEM_PFN >> PAGE_SHIFT;
 
        /* Find an area to use for the bootmem bitmap. */
 
@@ -215,7 +215,7 @@ void __init init_mmu (void)
 
        /* Set rasid register to a known value. */
 
-       set_rasid_register (ASID_ALL_RESERVED);
+       set_rasid_register (ASID_USER_FIRST);
 
        /* Set PTEVADDR special register to the start of the page
         * table, which is in kernel mappable space (ie. not
index 327c0f17187c0cb1fa5072ee2360789e193fac06..ae085332c607095281bf1ad963c0f6c213c5eeeb 100644 (file)
@@ -19,9 +19,8 @@
 #include <linux/linkage.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-
-#include <xtensa/cacheasm.h>
-#include <xtensa/cacheattrasm.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheasm.h>
 
 /* clear_page (page) */
 
@@ -74,104 +73,66 @@ ENTRY(copy_page)
 
        retw
 
-
 /*
- * void __flush_invalidate_cache_all(void)
+ * void __invalidate_icache_page(ulong start)
  */
 
-ENTRY(__flush_invalidate_cache_all)
+ENTRY(__invalidate_icache_page)
        entry   sp, 16
-       dcache_writeback_inv_all a2, a3
-       icache_invalidate_all a2, a3
-       retw
 
-/*
- * void __invalidate_icache_all(void)
- */
+       ___invalidate_icache_page a2 a3
+       isync
 
-ENTRY(__invalidate_icache_all)
-       entry   sp, 16
-       icache_invalidate_all a2, a3
        retw
 
 /*
- * void __flush_invalidate_dcache_all(void)
+ * void __invalidate_dcache_page(ulong start)
  */
 
-ENTRY(__flush_invalidate_dcache_all)
+ENTRY(__invalidate_dcache_page)
        entry   sp, 16
-       dcache_writeback_inv_all a2, a3
-       retw
-
 
-/*
- * void __flush_invalidate_cache_range(ulong start, ulong size)
- */
+       ___invalidate_dcache_page a2 a3
+       dsync
 
-ENTRY(__flush_invalidate_cache_range)
-       entry   sp, 16
-       mov     a4, a2
-       mov     a5, a3
-       dcache_writeback_inv_region a4, a5, a6
-       icache_invalidate_region a2, a3, a4
        retw
 
 /*
- * void __invalidate_icache_page(ulong start)
+ * void __flush_invalidate_dcache_page(ulong start)
  */
 
-ENTRY(__invalidate_icache_page)
+ENTRY(__flush_invalidate_dcache_page)
        entry   sp, 16
-       movi    a3, PAGE_SIZE
-       icache_invalidate_region a2, a3, a4
-       retw
 
-/*
- * void __invalidate_dcache_page(ulong start)
- */
+       ___flush_invalidate_dcache_page a2 a3
 
-ENTRY(__invalidate_dcache_page)
-       entry   sp, 16
-       movi    a3, PAGE_SIZE
-       dcache_invalidate_region a2, a3, a4
+       dsync
        retw
 
 /*
- * void __invalidate_icache_range(ulong start, ulong size)
+ * void __flush_dcache_page(ulong start)
  */
 
-ENTRY(__invalidate_icache_range)
+ENTRY(__flush_dcache_page)
        entry   sp, 16
-       icache_invalidate_region a2, a3, a4
-       retw
 
-/*
- * void __invalidate_dcache_range(ulong start, ulong size)
- */
+       ___flush_dcache_page a2 a3
 
-ENTRY(__invalidate_dcache_range)
-       entry   sp, 16
-       dcache_invalidate_region a2, a3, a4
+       dsync
        retw
 
-/*
- * void __flush_dcache_page(ulong start)
- */
 
-ENTRY(__flush_dcache_page)
-       entry   sp, 16
-       movi    a3, PAGE_SIZE
-       dcache_writeback_region a2, a3, a4
-       retw
 
 /*
- * void __flush_invalidate_dcache_page(ulong start)
+ * void __invalidate_icache_range(ulong start, ulong size)
  */
 
-ENTRY(__flush_invalidate_dcache_page)
+ENTRY(__invalidate_icache_range)
        entry   sp, 16
-       movi    a3, PAGE_SIZE
-       dcache_writeback_inv_region a2, a3, a4
+
+       ___invalidate_icache_range a2 a3 a4
+       isync
+
        retw
 
 /*
@@ -180,195 +141,69 @@ ENTRY(__flush_invalidate_dcache_page)
 
 ENTRY(__flush_invalidate_dcache_range)
        entry   sp, 16
-       dcache_writeback_inv_region a2, a3, a4
-       retw
 
-/*
- * void __invalidate_dcache_all(void)
- */
+       ___flush_invalidate_dcache_range a2 a3 a4
+       dsync
 
-ENTRY(__invalidate_dcache_all)
-       entry   sp, 16
-       dcache_invalidate_all a2, a3
        retw
 
 /*
- * void __flush_invalidate_dcache_page_phys(ulong start)
+ * void _flush_dcache_range(ulong start, ulong size)
  */
 
-ENTRY(__flush_invalidate_dcache_page_phys)
+ENTRY(__flush_dcache_range)
        entry   sp, 16
 
-       movi    a3, XCHAL_DCACHE_SIZE
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
-
-1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
-
-       ldct    a6, a3
+       ___flush_dcache_range a2 a3 a4
        dsync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a3, 2, 1b
-       retw
 
-2:     diwbi   a3, 0
-       bgeui   a3, 2, 1b
        retw
 
-ENTRY(check_dcache_low0)
-       entry   sp, 16
-
-       movi    a3, XCHAL_DCACHE_SIZE / 4
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
-
-1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
-
-       ldct    a6, a3
-       dsync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a3, 2, 1b
-       retw
-
-2:     j 2b
-
-ENTRY(check_dcache_high0)
-       entry   sp, 16
-
-       movi    a5, XCHAL_DCACHE_SIZE / 4
-       movi    a3, XCHAL_DCACHE_SIZE / 2
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
-
-1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
-       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
-
-       ldct    a6, a3
-       dsync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a5, 2, 1b
-       retw
-
-2:     j 2b
+/*
+ * void _invalidate_dcache_range(ulong start, ulong size)
+ */
 
-ENTRY(check_dcache_low1)
+ENTRY(__invalidate_dcache_range)
        entry   sp, 16
 
-       movi    a5, XCHAL_DCACHE_SIZE / 4
-       movi    a3, XCHAL_DCACHE_SIZE * 3 / 4
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
+       ___invalidate_dcache_range a2 a3 a4
 
-1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
-       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
 
-       ldct    a6, a3
-       dsync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a5, 2, 1b
        retw
 
-2:     j 2b
+/*
+ * void _invalidate_icache_all(void)
+ */
 
-ENTRY(check_dcache_high1)
+ENTRY(__invalidate_icache_all)
        entry   sp, 16
 
-       movi    a5, XCHAL_DCACHE_SIZE / 4
-       movi    a3, XCHAL_DCACHE_SIZE
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
-
-1:     addi    a3, a3, -XCHAL_DCACHE_LINESIZE
-       addi    a5, a5, -XCHAL_DCACHE_LINESIZE
+       ___invalidate_icache_all a2 a3
+       isync
 
-       ldct    a6, a3
-       dsync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a5, 2, 1b
        retw
 
-2:     j 2b
-
-
 /*
- * void __invalidate_icache_page_phys(ulong start)
+ * void _flush_invalidate_dcache_all(void)
  */
 
-ENTRY(__invalidate_icache_page_phys)
+ENTRY(__flush_invalidate_dcache_all)
        entry   sp, 16
 
-       movi    a3, XCHAL_ICACHE_SIZE
-       movi    a4, PAGE_MASK | 1
-       addi    a2, a2, 1
-
-1:     addi    a3, a3, -XCHAL_ICACHE_LINESIZE
-
-       lict    a6, a3
-       isync
-       and     a6, a6, a4
-       beq     a6, a2, 2f
-       bgeui   a3, 2, 1b
-       retw
+       ___flush_invalidate_dcache_all a2 a3
+       dsync
 
-2:     iii     a3, 0
-       bgeui   a3, 2, 1b
        retw
 
+/*
+ * void _invalidate_dcache_all(void)
+ */
 
-#if 0
-
-       movi    a3, XCHAL_DCACHE_WAYS - 1
-       movi    a4, PAGE_SIZE
-
-1:     mov     a5, a2
-       add     a6, a2, a4
-
-2:     diwbi   a5, 0
-       diwbi   a5, XCHAL_DCACHE_LINESIZE
-       diwbi   a5, XCHAL_DCACHE_LINESIZE * 2
-       diwbi   a5, XCHAL_DCACHE_LINESIZE * 3
-
-       addi    a5, a5, XCHAL_DCACHE_LINESIZE * 4
-       blt     a5, a6, 2b
-
-       addi    a3, a3, -1
-       addi    a2, a2, XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS
-       bgez    a3, 1b
-
-       retw
-
-ENTRY(__invalidate_icache_page_index)
+ENTRY(__invalidate_dcache_all)
        entry   sp, 16
 
-       movi    a3, XCHAL_ICACHE_WAYS - 1
-       movi    a4, PAGE_SIZE
-
-1:     mov     a5, a2
-       add     a6, a2, a4
-
-2:     iii     a5, 0
-       iii     a5, XCHAL_ICACHE_LINESIZE
-       iii     a5, XCHAL_ICACHE_LINESIZE * 2
-       iii     a5, XCHAL_ICACHE_LINESIZE * 3
-
-       addi    a5, a5, XCHAL_ICACHE_LINESIZE * 4
-       blt     a5, a6, 2b
-
-       addi    a3, a3, -1
-       addi    a2, a2, XCHAL_ICACHE_SIZE / XCHAL_ICACHE_WAYS
-       bgez    a3, 2b
+       ___invalidate_dcache_all a2 a3
+       dsync
 
        retw
 
-#endif
-
-
-
-
-
-
index 0fefb866687463a562bfb6fa1ad5758d06393aec..239461d8ea888c150877a18d017a190ff6f61631 100644 (file)
 
 static inline void __flush_itlb_all (void)
 {
-       int way, index;
+       int w, i;
 
-       for (way = 0; way < XCHAL_ITLB_ARF_WAYS; way++) {
-               for (index = 0; index < ITLB_ENTRIES_PER_ARF_WAY; index++) {
-                       int entry = way + (index << PAGE_SHIFT);
-                       invalidate_itlb_entry_no_isync (entry);
+       for (w = 0; w < ITLB_ARF_WAYS; w++) {
+               for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) {
+                       int e = w + (i << PAGE_SHIFT);
+                       invalidate_itlb_entry_no_isync(e);
                }
        }
        asm volatile ("isync\n");
@@ -37,12 +37,12 @@ static inline void __flush_itlb_all (void)
 
 static inline void __flush_dtlb_all (void)
 {
-       int way, index;
+       int w, i;
 
-       for (way = 0; way < XCHAL_DTLB_ARF_WAYS; way++) {
-               for (index = 0; index < DTLB_ENTRIES_PER_ARF_WAY; index++) {
-                       int entry = way + (index << PAGE_SHIFT);
-                       invalidate_dtlb_entry_no_isync (entry);
+       for (w = 0; w < DTLB_ARF_WAYS; w++) {
+               for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) {
+                       int e = w + (i << PAGE_SHIFT);
+                       invalidate_dtlb_entry_no_isync(e);
                }
        }
        asm volatile ("isync\n");
@@ -63,21 +63,25 @@ void flush_tlb_all (void)
 
 void flush_tlb_mm(struct mm_struct *mm)
 {
-#if 0
-       printk("[tlbmm<%lx>]\n", (unsigned long)mm->context);
-#endif
-
        if (mm == current->active_mm) {
                int flags;
                local_save_flags(flags);
-               get_new_mmu_context(mm, asid_cache);
-               set_rasid_register(ASID_INSERT(mm->context));
+               __get_new_mmu_context(mm);
+               __load_mmu_context(mm);
                local_irq_restore(flags);
        }
        else
                mm->context = 0;
 }
 
+#define _ITLB_ENTRIES (ITLB_ARF_WAYS << XCHAL_ITLB_ARF_ENTRIES_LOG2)
+#define _DTLB_ENTRIES (DTLB_ARF_WAYS << XCHAL_DTLB_ARF_ENTRIES_LOG2)
+#if _ITLB_ENTRIES > _DTLB_ENTRIES
+# define _TLB_ENTRIES _ITLB_ENTRIES
+#else
+# define _TLB_ENTRIES _DTLB_ENTRIES
+#endif
+
 void flush_tlb_range (struct vm_area_struct *vma,
                      unsigned long start, unsigned long end)
 {
@@ -93,7 +97,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
 #endif
        local_save_flags(flags);
 
-       if (end-start + (PAGE_SIZE-1) <= SMALLEST_NTLB_ENTRIES << PAGE_SHIFT) {
+       if (end-start + (PAGE_SIZE-1) <= _TLB_ENTRIES << PAGE_SHIFT) {
                int oldpid = get_rasid_register();
                set_rasid_register (ASID_INSERT(mm->context));
                start &= PAGE_MASK;
@@ -111,9 +115,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
 
                set_rasid_register(oldpid);
        } else {
-               get_new_mmu_context(mm, asid_cache);
-               if (mm == current->active_mm)
-                       set_rasid_register(ASID_INSERT(mm->context));
+               flush_tlb_mm(mm);
        }
        local_irq_restore(flags);
 }
@@ -123,10 +125,6 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
        struct mm_struct* mm = vma->vm_mm;
        unsigned long flags;
        int oldpid;
-#if 0
-       printk("[tlbpage<%02lx,%08lx>]\n",
-                       (unsigned long)mm->context, page);
-#endif
 
        if(mm->context == NO_CONTEXT)
                return;
@@ -142,404 +140,5 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
        set_rasid_register(oldpid);
 
        local_irq_restore(flags);
-
-#if 0
-       flush_tlb_all();
-       return;
-#endif
-}
-
-
-#ifdef DEBUG_TLB
-
-#define USE_ITLB  0
-#define USE_DTLB  1
-
-struct way_config_t {
-       int indicies;
-       int indicies_log2;
-       int pgsz_log2;
-       int arf;
-};
-
-static struct way_config_t itlb[XCHAL_ITLB_WAYS] =
-{
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ARF)
-       },
-       { XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES_LOG2),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, PAGESZ_LOG2_MIN),
-         XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ARF)
-       }
-};
-
-static struct way_config_t dtlb[XCHAL_DTLB_WAYS] =
-{
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ARF)
-       },
-       { XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES_LOG2),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, PAGESZ_LOG2_MIN),
-         XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ARF)
-       }
-};
-
-/*  Total number of entries:  */
-#define ITLB_TOTAL_ENTRIES     \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES) + \
-               XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES)
-#define DTLB_TOTAL_ENTRIES     \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES) + \
-               XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES)
-
-
-typedef struct {
-    unsigned           va;
-    unsigned           pa;
-    unsigned char      asid;
-    unsigned char      ca;
-    unsigned char      way;
-    unsigned char      index;
-    unsigned char      pgsz_log2;      /* 0 .. 32 */
-    unsigned char      type;           /* 0=ITLB 1=DTLB */
-} tlb_dump_entry_t;
-
-/*  Return -1 if a precedes b, +1 if a follows b, 0 if same:  */
-int cmp_tlb_dump_info( tlb_dump_entry_t *a, tlb_dump_entry_t *b )
-{
-    if (a->asid < b->asid) return -1;
-    if (a->asid > b->asid) return  1;
-    if (a->va < b->va) return -1;
-    if (a->va > b->va) return  1;
-    if (a->pa < b->pa) return -1;
-    if (a->pa > b->pa) return  1;
-    if (a->ca < b->ca) return -1;
-    if (a->ca > b->ca) return  1;
-    if (a->way < b->way) return -1;
-    if (a->way > b->way) return  1;
-    if (a->index < b->index) return -1;
-    if (a->index > b->index) return  1;
-    return 0;
-}
-
-void sort_tlb_dump_info( tlb_dump_entry_t *t, int n )
-{
-    int i, j;
-    /*  Simple O(n*n) sort:  */
-    for (i = 0; i < n-1; i++)
-       for (j = i+1; j < n; j++)
-           if (cmp_tlb_dump_info(t+i, t+j) > 0) {
-               tlb_dump_entry_t tmp = t[i];
-               t[i] = t[j];
-               t[j] = tmp;
-           }
-}
-
-
-static tlb_dump_entry_t itlb_dump_info[ITLB_TOTAL_ENTRIES];
-static tlb_dump_entry_t dtlb_dump_info[DTLB_TOTAL_ENTRIES];
-
-
-static inline char *way_type (int type)
-{
-       return type ? "autorefill" : "non-autorefill";
-}
-
-void print_entry (struct way_config_t *way_info,
-                 unsigned int way,
-                 unsigned int index,
-                 unsigned int virtual,
-                 unsigned int translation)
-{
-       char valid_chr;
-       unsigned int va, pa, asid, ca;
-
-       va = virtual &
-               ~((1 << (way_info->pgsz_log2 + way_info->indicies_log2)) - 1);
-       asid = virtual & ((1 << XCHAL_MMU_ASID_BITS) - 1);
-       pa = translation & ~((1 << way_info->pgsz_log2) - 1);
-       ca = translation & ((1 << XCHAL_MMU_CA_BITS) - 1);
-       valid_chr = asid ? 'V' : 'I';
-
-       /* Compute and incorporate the effect of the index bits on the
-        * va.  It's more useful for kernel debugging, since we always
-        * want to know the effective va anyway. */
-
-       va += index << way_info->pgsz_log2;
-
-       printk ("\t[%d,%d] (%c) vpn 0x%.8x  ppn 0x%.8x  asid 0x%.2x  am 0x%x\n",
-               way, index, valid_chr, va, pa, asid, ca);
-}
-
-void print_itlb_entry (struct way_config_t *way_info, int way, int index)
-{
-       print_entry (way_info, way, index,
-                    read_itlb_virtual (way + (index << way_info->pgsz_log2)),
-                    read_itlb_translation (way + (index << way_info->pgsz_log2)));
-}
-
-void print_dtlb_entry (struct way_config_t *way_info, int way, int index)
-{
-       print_entry (way_info, way, index,
-                    read_dtlb_virtual (way + (index << way_info->pgsz_log2)),
-                    read_dtlb_translation (way + (index << way_info->pgsz_log2)));
-}
-
-void dump_itlb (void)
-{
-       int way, index;
-
-       printk ("\nITLB: ways = %d\n", XCHAL_ITLB_WAYS);
-
-       for (way = 0; way < XCHAL_ITLB_WAYS; way++) {
-               printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
-                       way, itlb[way].indicies,
-                       itlb[way].pgsz_log2, way_type(itlb[way].arf));
-               for (index = 0; index < itlb[way].indicies; index++) {
-                       print_itlb_entry(&itlb[way], way, index);
-               }
-       }
-}
-
-void dump_dtlb (void)
-{
-       int way, index;
-
-       printk ("\nDTLB: ways = %d\n", XCHAL_DTLB_WAYS);
-
-       for (way = 0; way < XCHAL_DTLB_WAYS; way++) {
-               printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
-                       way, dtlb[way].indicies,
-                       dtlb[way].pgsz_log2, way_type(dtlb[way].arf));
-               for (index = 0; index < dtlb[way].indicies; index++) {
-                       print_dtlb_entry(&dtlb[way], way, index);
-               }
-       }
-}
-
-void dump_tlb (tlb_dump_entry_t *tinfo, struct way_config_t *config,
-               int entries, int ways, int type, int show_invalid)
-{
-    tlb_dump_entry_t *e = tinfo;
-    int way, i;
-
-    /*  Gather all info:  */
-    for (way = 0; way < ways; way++) {
-       struct way_config_t *cfg = config + way;
-       for (i = 0; i < cfg->indicies; i++) {
-           unsigned wayindex = way + (i << cfg->pgsz_log2);
-           unsigned vv = (type ? read_dtlb_virtual (wayindex)
-                               : read_itlb_virtual (wayindex));
-           unsigned pp = (type ? read_dtlb_translation (wayindex)
-                               : read_itlb_translation (wayindex));
-
-           /* Compute and incorporate the effect of the index bits on the
-            * va.  It's more useful for kernel debugging, since we always
-            * want to know the effective va anyway. */
-
-           e->va = (vv & ~((1 << (cfg->pgsz_log2 + cfg->indicies_log2)) - 1));
-           e->va += (i << cfg->pgsz_log2);
-           e->pa = (pp & ~((1 << cfg->pgsz_log2) - 1));
-           e->asid = (vv & ((1 << XCHAL_MMU_ASID_BITS) - 1));
-           e->ca = (pp & ((1 << XCHAL_MMU_CA_BITS) - 1));
-           e->way = way;
-           e->index = i;
-           e->pgsz_log2 = cfg->pgsz_log2;
-           e->type = type;
-           e++;
-       }
-    }
-#if 1
-    /*  Sort by ASID and VADDR:  */
-    sort_tlb_dump_info (tinfo, entries);
-#endif
-
-    /*  Display all sorted info:  */
-    printk ("\n%cTLB dump:\n", (type ? 'D' : 'I'));
-    for (e = tinfo, i = 0; i < entries; i++, e++) {
-#if 0
-       if (e->asid == 0 && !show_invalid)
-           continue;
-#endif
-       printk ("%c way=%d i=%d  ASID=%02X V=%08X -> P=%08X CA=%X (%d %cB)\n",
-               (e->type ? 'D' : 'I'), e->way, e->index,
-               e->asid, e->va, e->pa, e->ca,
-               (1 << (e->pgsz_log2 % 10)),
-               " kMG"[e->pgsz_log2 / 10]
-               );
-    }
-}
-
-void dump_tlbs2 (int showinv)
-{
-    dump_tlb (itlb_dump_info, itlb, ITLB_TOTAL_ENTRIES, XCHAL_ITLB_WAYS, 0, showinv);
-    dump_tlb (dtlb_dump_info, dtlb, DTLB_TOTAL_ENTRIES, XCHAL_DTLB_WAYS, 1, showinv);
-}
-
-void dump_all_tlbs (void)
-{
-    dump_tlbs2 (1);
-}
-
-void dump_valid_tlbs (void)
-{
-    dump_tlbs2 (0);
 }
 
-
-void dump_tlbs (void)
-{
-       dump_itlb();
-       dump_dtlb();
-}
-
-void dump_cache_tag(int dcache, int idx)
-{
-       int w, i, s, e;
-       unsigned long tag, index;
-       unsigned long num_lines, num_ways, cache_size, line_size;
-
-       num_ways = dcache ? XCHAL_DCACHE_WAYS : XCHAL_ICACHE_WAYS;
-       cache_size = dcache ? XCHAL_DCACHE_SIZE : XCHAL_ICACHE_SIZE;
-       line_size = dcache ? XCHAL_DCACHE_LINESIZE : XCHAL_ICACHE_LINESIZE;
-
-       num_lines = cache_size / num_ways;
-
-       s = 0; e = num_lines;
-
-       if (idx >= 0)
-               e = (s = idx * line_size) + 1;
-
-       for (i = s; i < e; i+= line_size) {
-               printk("\nline %#08x:", i);
-               for (w = 0; w < num_ways; w++) {
-                       index = w * num_lines + i;
-                       if (dcache)
-                               __asm__ __volatile__("ldct %0, %1\n\t"
-                                               : "=a"(tag) : "a"(index));
-                       else
-                               __asm__ __volatile__("lict %0, %1\n\t"
-                                               : "=a"(tag) : "a"(index));
-
-                       printk(" %#010lx", tag);
-               }
-       }
-       printk ("\n");
-}
-
-void dump_icache(int index)
-{
-       unsigned long data, addr;
-       int w, i;
-
-       const unsigned long num_ways = XCHAL_ICACHE_WAYS;
-       const unsigned long cache_size = XCHAL_ICACHE_SIZE;
-       const unsigned long line_size = XCHAL_ICACHE_LINESIZE;
-       const unsigned long num_lines = cache_size / num_ways / line_size;
-
-       for (w = 0; w < num_ways; w++) {
-               printk ("\nWay %d", w);
-
-               for (i = 0; i < line_size; i+= 4) {
-                       addr = w * num_lines + index * line_size + i;
-                       __asm__ __volatile__("licw %0, %1\n\t"
-                                       : "=a"(data) : "a"(addr));
-                       printk(" %#010lx", data);
-               }
-       }
-       printk ("\n");
-}
-
-void dump_cache_tags(void)
-{
-       printk("Instruction cache\n");
-       dump_cache_tag(0, -1);
-       printk("Data cache\n");
-       dump_cache_tag(1, -1);
-}
-
-#endif
index 5c947cae75207d91825ead1b34cf59fdc516bcf7..2f4f20ffe666adadfe676aa07aa83aff7c1beee3 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 
-#include <xtensa/simcall.h>
+#include <asm/platform/simcall.h>
 
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
 #define SERIAL_MAX_NUM_LINES 1
 #define SERIAL_TIMER_VALUE (20 * HZ)
 
@@ -191,7 +195,7 @@ static int rs_read_proc(char *page, char **start, off_t off, int count,
 }
 
 
-static const struct tty_operations serial_ops = {
+static struct tty_operations serial_ops = {
        .open = rs_open,
        .close = rs_close,
        .write = rs_write,
index 15d64414bd6018e2394d3485ec6070730614eb5a..8ebfc87612298115875a440293266120865dbe35 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/timer.h>
 #include <linux/platform_device.h>
 
-#include <xtensa/simcall.h>
+#include <asm/platform/simcall.h>
 
 #define DRIVER_NAME "iss-netdev"
 #define ETH_MAX_PACKET 1500
index 4f83fd92237756e74a959565ca9b6f8b76440165..a541b42c08e343f848d292a1ebfda4a0e82d5090 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/blktrace_api.h>
@@ -128,13 +129,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
 }
 EXPORT_SYMBOL(blk_get_backing_dev_info);
 
-void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data)
-{
-       q->activity_fn = fn;
-       q->activity_data = data;
-}
-EXPORT_SYMBOL(blk_queue_activity_fn);
-
 /**
  * blk_queue_prep_rq - set a prepare_request function for queue
  * @q:         queue
@@ -237,8 +231,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
         * by default assume old behaviour and bounce for any highmem page
         */
        blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-
-       blk_queue_activity_fn(q, NULL, NULL);
 }
 
 EXPORT_SYMBOL(blk_queue_make_request);
@@ -2695,9 +2687,6 @@ static inline void add_request(request_queue_t * q, struct request * req)
 {
        drive_stat_acct(req, req->nr_sectors, 1);
 
-       if (q->activity_fn)
-               q->activity_fn(q->activity_data, rq_data_dir(req));
-
        /*
         * elevator indicated where it wants this request to be
         * inserted at elevator_merge time
@@ -3235,10 +3224,12 @@ void submit_bio(int rw, struct bio *bio)
        BIO_BUG_ON(!bio->bi_size);
        BIO_BUG_ON(!bio->bi_io_vec);
        bio->bi_rw |= rw;
-       if (rw & WRITE)
+       if (rw & WRITE) {
                count_vm_events(PGPGOUT, count);
-       else
+       } else {
+               task_io_account_read(bio->bi_size);
                count_vm_events(PGPGIN, count);
+       }
 
        if (unlikely(block_dump)) {
                char b[BDEVNAME_SIZE];
index b3e210723a71f637605852b7d8136ef594af95d2..f322b6a441d82fbe7db9a177ac0837fc54618cf2 100644 (file)
@@ -228,6 +228,7 @@ static int sg_io(struct file *file, request_queue_t *q,
        struct request *rq;
        char sense[SCSI_SENSE_BUFFERSIZE];
        unsigned char cmd[BLK_MAX_CDB];
+       struct bio *bio;
 
        if (hdr->interface_id != 'S')
                return -EINVAL;
@@ -270,13 +271,6 @@ static int sg_io(struct file *file, request_queue_t *q,
 
        rq->cmd_type = REQ_TYPE_BLOCK_PC;
 
-       /*
-        * bounce this after holding a reference to the original bio, it's
-        * needed for proper unmapping
-        */
-       if (rq->bio)
-               blk_queue_bounce(q, &rq->bio);
-
        rq->timeout = jiffies_to_msecs(hdr->timeout);
        if (!rq->timeout)
                rq->timeout = q->sg_timeout;
@@ -308,6 +302,7 @@ static int sg_io(struct file *file, request_queue_t *q,
        if (ret)
                goto out;
 
+       bio = rq->bio;
        rq->retries = 0;
 
        start_time = jiffies;
@@ -338,6 +333,7 @@ static int sg_io(struct file *file, request_queue_t *q,
                        hdr->sb_len_wr = len;
        }
 
+       rq->bio = bio;
        if (blk_rq_unmap_user(rq))
                ret = -EFAULT;
 
index 2dfe7f170b4893bc6b5bdf5870c9ac3b77b89c9d..15eab9db9be410dfe12d990b4bdc2b417e798050 100644 (file)
@@ -24,7 +24,7 @@
 
 #define SHA384_DIGEST_SIZE 48
 #define SHA512_DIGEST_SIZE 64
-#define SHA384_HMAC_BLOCK_SIZE  96
+#define SHA384_HMAC_BLOCK_SIZE 128
 #define SHA512_HMAC_BLOCK_SIZE 128
 
 struct sha512_ctx {
index 4929e923b5c6fa15632cd45afd4e4df62b294ef6..e7da9fa724ec5f50aa70040df67c10c2d7cbf2fe 100644 (file)
@@ -80,4 +80,6 @@ source "drivers/rtc/Kconfig"
 
 source "drivers/dma/Kconfig"
 
+source "drivers/kvm/Kconfig"
+
 endmenu
index 50f76da598c95f67d86d7097c57fa2b03ee08909..0dd96d1afd39246bb3e625c60b9f30bd386305a4 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_SPI)             += spi/
 obj-$(CONFIG_PCCARD)           += pcmcia/
 obj-$(CONFIG_DIO)              += dio/
 obj-$(CONFIG_SBUS)             += sbus/
+obj-$(CONFIG_KVM)              += kvm/
 obj-$(CONFIG_ZORRO)            += zorro/
 obj-$(CONFIG_MAC)              += macintosh/
 obj-$(CONFIG_ATA_OVER_ETH)     += block/aoe/
index a165b716771408c589b53e0aa074b03347e2e252..fc0ae5eb05d81c5c03e708d226ec1bbb3f2c25aa 100644 (file)
@@ -2,4 +2,4 @@
 fore200e_mkfirm
 fore200e_pca_fw.c
 pca200e.bin
-
+pca200e_ecd.bin2
index 6c59baa887a8c7d1fc1352034303b07ba85eec05..e736119b64970ab6175c161e91a95d4412197bb8 100644 (file)
 #define BT_DEBUG_ENABLE        1       /* Generic messages */
 #define BT_DEBUG_MSG   2       /* Prints all request/response buffers */
 #define BT_DEBUG_STATES        4       /* Verbose look at state changes */
+/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized
+   value */
 
-static int bt_debug = BT_DEBUG_OFF;
+static int bt_debug; /* 0 == BT_DEBUG_OFF */
 
 module_param(bt_debug, int, 0644);
 MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
index e257835a9a73364fcc66ee5ed86f9cf7392d8b07..ff2d052177cb9250c17198b66e5f510db1b52267 100644 (file)
@@ -834,7 +834,7 @@ static const struct file_operations ipmi_fops = {
 
 #define DEVICE_NAME     "ipmidev"
 
-static int ipmi_major = 0;
+static int ipmi_major;
 module_param(ipmi_major, int, 0);
 MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
                 " default, or if you set it to zero, it will choose the next"
index 5703ee28e1cc0b97adb7488db3b843b2715290ca..4e4691a538901b7b728950edefcb33c5475abc56 100644 (file)
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
 
-static int initialized = 0;
+static int initialized;
 
 #ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_ipmi_root = NULL;
+static struct proc_dir_entry *proc_ipmi_root;
 #endif /* CONFIG_PROC_FS */
 
 /* Remain in auto-maintenance mode for this amount of time (in ms). */
@@ -2142,8 +2142,7 @@ cleanup_bmc_device(struct kref *ref)
        bmc = container_of(ref, struct bmc_device, refcount);
 
        remove_files(bmc);
-       if (bmc->dev)
-               platform_device_unregister(bmc->dev);
+       platform_device_unregister(bmc->dev);
        kfree(bmc);
 }
 
@@ -2341,8 +2340,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
 
                while (ipmi_find_bmc_prod_dev_id(&ipmidriver,
                                                 bmc->id.product_id,
-                                                bmc->id.device_id))
-               {
+                                                bmc->id.device_id)) {
                        if (!warn_printed) {
                                printk(KERN_WARNING PFX
                                       "This machine has two different BMCs"
@@ -4043,7 +4041,7 @@ static void send_panic_events(char *str)
 }
 #endif /* CONFIG_IPMI_PANIC_EVENT */
 
-static int has_panicked = 0;
+static int has_panicked;
 
 static int panic_event(struct notifier_block *this,
                       unsigned long         event,
index 597eb4f88b845b2c69f77b7d2e4508aaea0cd289..9d23136e598a74ce54c4a52d6a250f8f8a6202b5 100644 (file)
@@ -58,10 +58,10 @@ static int poweroff_powercycle;
 static int ifnum_to_use = -1;
 
 /* Our local state. */
-static int ready = 0;
+static int ready;
 static ipmi_user_t ipmi_user;
 static int ipmi_ifnum;
-static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;
+static void (*specific_poweroff_func)(ipmi_user_t user);
 
 /* Holds the old poweroff function so we can restore it on removal. */
 static void (*old_poweroff_func)(void);
@@ -182,7 +182,7 @@ static int ipmi_request_in_rc_mode(ipmi_user_t            user,
 #define IPMI_MOTOROLA_MANUFACTURER_ID          0x0000A1
 #define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID      0x0051
 
-static void (*atca_oem_poweroff_hook)(ipmi_user_t user) = NULL;
+static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
 
 static void pps_poweroff_atca (ipmi_user_t user)
 {
index 81a0c89598e790bc767b6552642da1dc69b3968f..f1afd26a509fa037b3e777a7d3dbe3c5d176bba1 100644 (file)
@@ -845,7 +845,7 @@ static void request_events(void *send_info)
        atomic_set(&smi_info->req_events, 1);
 }
 
-static int initialized = 0;
+static int initialized;
 
 static void smi_timeout(unsigned long data)
 {
@@ -1018,17 +1018,17 @@ static int num_ports;
 static int           irqs[SI_MAX_PARMS];
 static int num_irqs;
 static int           regspacings[SI_MAX_PARMS];
-static int num_regspacings = 0;
+static int num_regspacings;
 static int           regsizes[SI_MAX_PARMS];
-static int num_regsizes = 0;
+static int num_regsizes;
 static int           regshifts[SI_MAX_PARMS];
-static int num_regshifts = 0;
+static int num_regshifts;
 static int slave_addrs[SI_MAX_PARMS];
-static int num_slave_addrs = 0;
+static int num_slave_addrs;
 
 #define IPMI_IO_ADDR_SPACE  0
 #define IPMI_MEM_ADDR_SPACE 1
-static char *addr_space_to_str[] = { "I/O", "mem" };
+static char *addr_space_to_str[] = { "i/o", "mem" };
 
 static int hotmod_handler(const char *val, struct kernel_param *kp);
 
@@ -1397,20 +1397,7 @@ static struct hotmod_vals hotmod_as[] = {
        { "i/o",        IPMI_IO_ADDR_SPACE },
        { NULL }
 };
-static int ipmi_strcasecmp(const char *s1, const char *s2)
-{
-       while (*s1 || *s2) {
-               if (!*s1)
-                       return -1;
-               if (!*s2)
-                       return 1;
-               if (*s1 != *s2)
-                       return *s1 - *s2;
-               s1++;
-               s2++;
-       }
-       return 0;
-}
+
 static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
 {
        char *s;
@@ -1424,7 +1411,7 @@ static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
        *s = '\0';
        s++;
        for (i = 0; hotmod_ops[i].name; i++) {
-               if (ipmi_strcasecmp(*curr, v[i].name) == 0) {
+               if (strcmp(*curr, v[i].name) == 0) {
                        *val = v[i].val;
                        *curr = s;
                        return 0;
@@ -1435,10 +1422,34 @@ static int parse_str(struct hotmod_vals *v, int *val, char *name, char **curr)
        return -EINVAL;
 }
 
+static int check_hotmod_int_op(const char *curr, const char *option,
+                              const char *name, int *val)
+{
+       char *n;
+
+       if (strcmp(curr, name) == 0) {
+               if (!option) {
+                       printk(KERN_WARNING PFX
+                              "No option given for '%s'\n",
+                              curr);
+                       return -EINVAL;
+               }
+               *val = simple_strtoul(option, &n, 0);
+               if ((*n != '\0') || (*option == '\0')) {
+                       printk(KERN_WARNING PFX
+                              "Bad option given for '%s'\n",
+                              curr);
+                       return -EINVAL;
+               }
+               return 1;
+       }
+       return 0;
+}
+
 static int hotmod_handler(const char *val, struct kernel_param *kp)
 {
        char *str = kstrdup(val, GFP_KERNEL);
-       int  rv = -EINVAL;
+       int  rv;
        char *next, *curr, *s, *n, *o;
        enum hotmod_op op;
        enum si_type si_type;
@@ -1450,13 +1461,15 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
        int irq;
        int ipmb;
        int ival;
+       int len;
        struct smi_info *info;
 
        if (!str)
                return -ENOMEM;
 
        /* Kill any trailing spaces, as we can get a "\n" from echo. */
-       ival = strlen(str) - 1;
+       len = strlen(str);
+       ival = len - 1;
        while ((ival >= 0) && isspace(str[ival])) {
                str[ival] = '\0';
                ival--;
@@ -1513,35 +1526,37 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                                *o = '\0';
                                o++;
                        }
-#define HOTMOD_INT_OPT(name, val) \
-                       if (ipmi_strcasecmp(curr, name) == 0) {         \
-                               if (!o) {                               \
-                                       printk(KERN_WARNING PFX         \
-                                              "No option given for '%s'\n", \
-                                               curr);                  \
-                                       goto out;                       \
-                               }                                       \
-                               val = simple_strtoul(o, &n, 0);         \
-                               if ((*n != '\0') || (*o == '\0')) {     \
-                                       printk(KERN_WARNING PFX         \
-                                              "Bad option given for '%s'\n", \
-                                              curr);                   \
-                                       goto out;                       \
-                               }                                       \
-                       }
-
-                       HOTMOD_INT_OPT("rsp", regspacing)
-                       else HOTMOD_INT_OPT("rsi", regsize)
-                       else HOTMOD_INT_OPT("rsh", regshift)
-                       else HOTMOD_INT_OPT("irq", irq)
-                       else HOTMOD_INT_OPT("ipmb", ipmb)
-                       else {
-                               printk(KERN_WARNING PFX
-                                      "Invalid hotmod option '%s'\n",
-                                      curr);
+                       rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
+                       if (rv < 0)
                                goto out;
-                       }
-#undef HOTMOD_INT_OPT
+                       else if (rv)
+                               continue;
+                       rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
+                       if (rv < 0)
+                               goto out;
+                       else if (rv)
+                               continue;
+                       rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
+                       if (rv < 0)
+                               goto out;
+                       else if (rv)
+                               continue;
+                       rv = check_hotmod_int_op(curr, o, "irq", &irq);
+                       if (rv < 0)
+                               goto out;
+                       else if (rv)
+                               continue;
+                       rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
+                       if (rv < 0)
+                               goto out;
+                       else if (rv)
+                               continue;
+
+                       rv = -EINVAL;
+                       printk(KERN_WARNING PFX
+                              "Invalid hotmod option '%s'\n",
+                              curr);
+                       goto out;
                }
 
                if (op == HM_ADD) {
@@ -1590,6 +1605,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                        mutex_unlock(&smi_infos_lock);
                }
        }
+       rv = len;
  out:
        kfree(str);
        return rv;
@@ -1610,11 +1626,11 @@ static __devinit void hardcode_find_bmc(void)
 
                info->addr_source = "hardcoded";
 
-               if (!si_type[i] || ipmi_strcasecmp(si_type[i], "kcs") == 0) {
+               if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
                        info->si_type = SI_KCS;
-               } else if (ipmi_strcasecmp(si_type[i], "smic") == 0) {
+               } else if (strcmp(si_type[i], "smic") == 0) {
                        info->si_type = SI_SMIC;
-               } else if (ipmi_strcasecmp(si_type[i], "bt") == 0) {
+               } else if (strcmp(si_type[i], "bt") == 0) {
                        info->si_type = SI_BT;
                } else {
                        printk(KERN_WARNING
@@ -1668,7 +1684,7 @@ static __devinit void hardcode_find_bmc(void)
 /* Once we get an ACPI failure, we don't try any more, because we go
    through the tables sequentially.  Once we don't find a table, there
    are no more. */
-static int acpi_failure = 0;
+static int acpi_failure;
 
 /* For GPE-type interrupts. */
 static u32 ipmi_acpi_gpe(void *context)
@@ -1779,7 +1795,6 @@ struct SPMITable {
 static __devinit int try_init_acpi(struct SPMITable *spmi)
 {
        struct smi_info  *info;
-       char             *io_type;
        u8               addr_space;
 
        if (spmi->IPMIlegacy != 1) {
@@ -1843,11 +1858,9 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
        info->io.regshift = spmi->addr.register_bit_offset;
 
        if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               io_type = "memory";
                info->io_setup = mem_setup;
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
        } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-               io_type = "I/O";
                info->io_setup = port_setup;
                info->io.addr_type = IPMI_MEM_ADDR_SPACE;
        } else {
@@ -2773,8 +2786,7 @@ static __devinit int init_ipmi_si(void)
 #endif
 
 #ifdef CONFIG_ACPI
-       if (si_trydefaults)
-               acpi_find_bmc();
+       acpi_find_bmc();
 #endif
 
 #ifdef CONFIG_PCI
index 90fb2a541916e2efba863662d4e3cffa35698af4..78280380a905ff82bbb49644f80b9926d5809ed1 100644 (file)
 
 static int nowayout = WATCHDOG_NOWAYOUT;
 
-static ipmi_user_t watchdog_user = NULL;
+static ipmi_user_t watchdog_user;
 static int watchdog_ifnum;
 
 /* Default the timeout to 10 seconds. */
 static int timeout = 10;
 
 /* The pre-timeout is disabled by default. */
-static int pretimeout = 0;
+static int pretimeout;
 
 /* Default action is to reset the board on a timeout. */
 static unsigned char action_val = WDOG_TIMEOUT_RESET;
@@ -156,10 +156,10 @@ static unsigned char preop_val = WDOG_PREOP_NONE;
 
 static char preop[16] = "preop_none";
 static DEFINE_SPINLOCK(ipmi_read_lock);
-static char data_to_read = 0;
+static char data_to_read;
 static DECLARE_WAIT_QUEUE_HEAD(read_q);
-static struct fasync_struct *fasync_q = NULL;
-static char pretimeout_since_last_heartbeat = 0;
+static struct fasync_struct *fasync_q;
+static char pretimeout_since_last_heartbeat;
 static char expect_close;
 
 static int ifnum_to_use = -1;
@@ -177,7 +177,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf);
 
 /* If true, the driver will start running as soon as it is configured
    and ready. */
-static int start_now = 0;
+static int start_now;
 
 static int set_param_int(const char *val, struct kernel_param *kp)
 {
@@ -300,16 +300,16 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
 
 /* If shutting down via IPMI, we ignore the heartbeat. */
-static int ipmi_ignore_heartbeat = 0;
+static int ipmi_ignore_heartbeat;
 
 /* Is someone using the watchdog?  Only one user is allowed. */
-static unsigned long ipmi_wdog_open = 0;
+static unsigned long ipmi_wdog_open;
 
 /* If set to 1, the heartbeat command will set the state to reset and
    start the timer.  The timer doesn't normally run when the driver is
    first opened until the heartbeat is set the first time, this
    variable is used to accomplish this. */
-static int ipmi_start_timer_on_heartbeat = 0;
+static int ipmi_start_timer_on_heartbeat;
 
 /* IPMI version of the BMC. */
 static unsigned char ipmi_version_major;
index 089020e0ee5aa83ce48ff8b15470724a45eafdc4..4f1813e04754117c5f046ff12513b8464339791a 100644 (file)
@@ -646,7 +646,8 @@ static inline size_t read_zero_pagealigned(char __user * buf, size_t size)
                        count = size;
 
                zap_page_range(vma, addr, count, NULL);
-               zeromap_page_range(vma, addr, count, PAGE_COPY);
+               if (zeromap_page_range(vma, addr, count, PAGE_COPY))
+                       break;
 
                size -= count;
                buf += count;
@@ -713,11 +714,14 @@ out:
 
 static int mmap_zero(struct file * file, struct vm_area_struct * vma)
 {
+       int err;
+
        if (vma->vm_flags & VM_SHARED)
                return shmem_zero_setup(vma);
-       if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
-               return -EAGAIN;
-       return 0;
+       err = zeromap_page_range(vma, vma->vm_start,
+                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+       BUG_ON(err == -EEXIST);
+       return err;
 }
 #else /* CONFIG_MMU */
 static ssize_t read_zero(struct file * file, char * buf, 
index 092a01cc02dae273cbce4b794b5a3834b60cbebe..13d0b1350a62ed5fb579e727b623cb027e86610c 100644 (file)
@@ -1203,7 +1203,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
 
 static int uuid_strategy(ctl_table *table, int __user *name, int nlen,
                         void __user *oldval, size_t __user *oldlenp,
-                        void __user *newval, size_t newlen, void **context)
+                        void __user *newval, size_t newlen)
 {
        unsigned char tmp_uuid[16], *uuid;
        unsigned int len;
index 8ab61ef97b4c7da1029203c42dbe68f244aab888..b6bcdbbf57b3fe5ab0810fc6221fcab1d9b744ed 100644 (file)
@@ -77,11 +77,11 @@ static struct clocksource clocksource_acpi_pm = {
 
 
 #ifdef CONFIG_PCI
-static int acpi_pm_good;
+static int __devinitdata acpi_pm_good;
 static int __init acpi_pm_good_setup(char *__str)
 {
-       acpi_pm_good = 1;
-       return 1;
+       acpi_pm_good = 1;
+       return 1;
 }
 __setup("acpi_pm_good", acpi_pm_good_setup);
 
index e816535ab305e33b06ec2368dc668fa43a4f3b21..879250d3d0690d40191dad3699ab139820894552 100644 (file)
@@ -53,7 +53,7 @@ config CRYPTO_DEV_PADLOCK_SHA
 
 config CRYPTO_DEV_GEODE
        tristate "Support for the Geode LX AES engine"
-       depends on CRYPTO && X86_32
+       depends on CRYPTO && X86_32 && PCI
        select CRYPTO_ALGAPI
        select CRYPTO_BLKCIPHER
        default m
index 88214943d00ad776a0977507c4b5d721ed894949..5969cec58dc155c2f21aea7e72c4b6d6aca9eb94 100644 (file)
@@ -687,8 +687,15 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 {
        struct request *rq = HWGROUP(drive)->rq;
+       ide_hwif_t *hwif = HWIF(drive);
        int stat, err, sense_key;
        
+       /* We may have bogus DMA interrupts in PIO state here */
+       if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) {
+               stat = hwif->INB(hwif->dma_status);
+               /* Should we force the bit as well ? */
+               hwif->OUTB(stat, hwif->dma_status);
+       }
        /* Check for errors. */
        stat = HWIF(drive)->INB(IDE_STATUS_REG);
        if (stat_ret)
index dad9c47ebb69bb0aa667689f701301a34118c115..5a5c565a32a8230959318ebe4e0e7b8c78093af1 100644 (file)
@@ -1000,10 +1000,6 @@ static int ide_init_queue(ide_drive_t *drive)
        /* needs drive->queue to be set */
        ide_toggle_bounce(drive, 1);
 
-       /* enable led activity for disk drives only */
-       if (drive->media == ide_disk && hwif->led_act)
-               blk_queue_activity_fn(q, hwif->led_act, drive);
-
        return 0;
 }
 
index 3ca581063f7247f3a7ed59af0f10d196e6b7da5f..7cb48576e479fbb1151f658441b887631f49dd68 100644 (file)
 
 #define PDC202_DEBUG_CABLE     0
 
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk("%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
 static const char *pdc_quirk_drives[] = {
        "QUANTUM FIREBALLlct08 08",
        "QUANTUM FIREBALLP KA6.4",
@@ -51,37 +59,11 @@ static const char *pdc_quirk_drives[] = {
        NULL
 };
 
-#define set_2regs(a, b)                                        \
-       do {                                            \
-               hwif->OUTB((a + adj), indexreg);        \
-               hwif->OUTB(b, datareg);                 \
-       } while(0)
-
-#define set_ultra(a, b, c)                             \
-       do {                                            \
-               set_2regs(0x10,(a));                    \
-               set_2regs(0x11,(b));                    \
-               set_2regs(0x12,(c));                    \
-       } while(0)
-
-#define set_ata2(a, b)                                 \
-       do {                                            \
-               set_2regs(0x0e,(a));                    \
-               set_2regs(0x0f,(b));                    \
-       } while(0)
-
-#define set_pio(a, b, c)                               \
-       do {                                            \
-               set_2regs(0x0c,(a));                    \
-               set_2regs(0x0d,(b));                    \
-               set_2regs(0x13,(c));                    \
-       } while(0)
-
-static u8 pdcnew_ratemask (ide_drive_t *drive)
+static u8 max_dma_rate(struct pci_dev *pdev)
 {
        u8 mode;
 
-       switch(HWIF(drive)->pci_dev->device) {
+       switch(pdev->device) {
                case PCI_DEVICE_ID_PROMISE_20277:
                case PCI_DEVICE_ID_PROMISE_20276:
                case PCI_DEVICE_ID_PROMISE_20275:
@@ -96,12 +78,21 @@ static u8 pdcnew_ratemask (ide_drive_t *drive)
                default:
                        return 0;
        }
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
+
        return mode;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+static u8 pdcnew_ratemask(ide_drive_t *drive)
+{
+       u8 mode = max_dma_rate(HWIF(drive)->pci_dev);
+
+       if (!eighty_ninty_three(drive))
+               mode = min_t(u8, mode, 1);
+
+       return  mode;
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list)
 {
        struct hd_driveid *id = drive->id;
 
@@ -121,43 +112,141 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
        return 0;
 }
 
-static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+/**
+ * get_indexed_reg - Get indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
+ */
+static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
+{
+       u8 value;
+
+       hwif->OUTB(index, hwif->dma_vendor1);
+       value = hwif->INB(hwif->dma_vendor3);
+
+       DBG("index[%02X] value[%02X]\n", index, value);
+       return value;
+}
+
+/**
+ * set_indexed_reg - Set indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
+ */
+static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
+{
+       hwif->OUTB(index, hwif->dma_vendor1);
+       hwif->OUTB(value, hwif->dma_vendor3);
+       DBG("index[%02X] value[%02X]\n", index, value);
+}
+
+/*
+ * ATA Timing Tables based on 133 MHz PLL output clock.
+ *
+ * If the PLL outputs 100 MHz clock, the ASIC hardware will set
+ * the timing registers automatically when "set features" command is
+ * issued to the device. However, if the PLL output clock is 133 MHz,
+ * the following tables must be used.
+ */
+static struct pio_timing {
+       u8 reg0c, reg0d, reg13;
+} pio_timings [] = {
+       { 0xfb, 0x2b, 0xac },   /* PIO mode 0, IORDY off, Prefetch off */
+       { 0x46, 0x29, 0xa4 },   /* PIO mode 1, IORDY off, Prefetch off */
+       { 0x23, 0x26, 0x64 },   /* PIO mode 2, IORDY off, Prefetch off */
+       { 0x27, 0x0d, 0x35 },   /* PIO mode 3, IORDY on,  Prefetch off */
+       { 0x23, 0x09, 0x25 },   /* PIO mode 4, IORDY on,  Prefetch off */
+};
+
+static struct mwdma_timing {
+       u8 reg0e, reg0f;
+} mwdma_timings [] = {
+       { 0xdf, 0x5f },         /* MWDMA mode 0 */
+       { 0x6b, 0x27 },         /* MWDMA mode 1 */
+       { 0x69, 0x25 },         /* MWDMA mode 2 */
+};
+
+static struct udma_timing {
+       u8 reg10, reg11, reg12;
+} udma_timings [] = {
+       { 0x4a, 0x0f, 0xd5 },   /* UDMA mode 0 */
+       { 0x3a, 0x0a, 0xd0 },   /* UDMA mode 1 */
+       { 0x2a, 0x07, 0xcd },   /* UDMA mode 2 */
+       { 0x1a, 0x05, 0xcd },   /* UDMA mode 3 */
+       { 0x1a, 0x03, 0xcd },   /* UDMA mode 4 */
+       { 0x1a, 0x02, 0xcb },   /* UDMA mode 5 */
+       { 0x1a, 0x01, 0xcb },   /* UDMA mode 6 */
+};
+
+static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       unsigned long indexreg  = hwif->dma_vendor1;
-       unsigned long datareg   = hwif->dma_vendor3;
-       u8 thold                = 0x10;
-       u8 adj                  = (drive->dn%2) ? 0x08 : 0x00;
-       u8 speed                = ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
-
-       if (speed == XFER_UDMA_2) {
-               hwif->OUTB((thold + adj), indexreg);
-               hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
-       }
+       u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
+       int                     err;
 
-       switch (speed) {
-               case XFER_UDMA_7:
-                       speed = XFER_UDMA_6;
-               case XFER_UDMA_6:       set_ultra(0x1a, 0x01, 0xcb); break;
-               case XFER_UDMA_5:       set_ultra(0x1a, 0x02, 0xcb); break;
-               case XFER_UDMA_4:       set_ultra(0x1a, 0x03, 0xcd); break;
-               case XFER_UDMA_3:       set_ultra(0x1a, 0x05, 0xcd); break;
-               case XFER_UDMA_2:       set_ultra(0x2a, 0x07, 0xcd); break;
-               case XFER_UDMA_1:       set_ultra(0x3a, 0x0a, 0xd0); break;
-               case XFER_UDMA_0:       set_ultra(0x4a, 0x0f, 0xd5); break;
-               case XFER_MW_DMA_2:     set_ata2(0x69, 0x25); break;
-               case XFER_MW_DMA_1:     set_ata2(0x6b, 0x27); break;
-               case XFER_MW_DMA_0:     set_ata2(0xdf, 0x5f); break;
-               case XFER_PIO_4:        set_pio(0x23, 0x09, 0x25); break;
-               case XFER_PIO_3:        set_pio(0x27, 0x0d, 0x35); break;
-               case XFER_PIO_2:        set_pio(0x23, 0x26, 0x64); break;
-               case XFER_PIO_1:        set_pio(0x46, 0x29, 0xa4); break;
-               case XFER_PIO_0:        set_pio(0xfb, 0x2b, 0xac); break;
-               default:
-                       ;
-       }
+       speed = ide_rate_filter(pdcnew_ratemask(drive), speed);
+
+       /*
+        * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
+        * automatically set the timing registers based on 100 MHz PLL output.
+        */
+       err = ide_config_drive_speed(drive, speed);
+
+       /*
+        * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
+        * chips, we must override the default register settings...
+        */
+       if (max_dma_rate(hwif->pci_dev) == 4) {
+               u8 mode = speed & 0x07;
+
+               switch (speed) {
+                       case XFER_UDMA_6:
+                       case XFER_UDMA_5:
+                       case XFER_UDMA_4:
+                       case XFER_UDMA_3:
+                       case XFER_UDMA_2:
+                       case XFER_UDMA_1:
+                       case XFER_UDMA_0:
+                               set_indexed_reg(hwif, 0x10 + adj,
+                                               udma_timings[mode].reg10);
+                               set_indexed_reg(hwif, 0x11 + adj,
+                                               udma_timings[mode].reg11);
+                               set_indexed_reg(hwif, 0x12 + adj,
+                                               udma_timings[mode].reg12);
+                               break;
+
+                       case XFER_MW_DMA_2:
+                       case XFER_MW_DMA_1:
+                       case XFER_MW_DMA_0:
+                               set_indexed_reg(hwif, 0x0e + adj,
+                                               mwdma_timings[mode].reg0e);
+                               set_indexed_reg(hwif, 0x0f + adj,
+                                               mwdma_timings[mode].reg0f);
+                               break;
+                       case XFER_PIO_4:
+                       case XFER_PIO_3:
+                       case XFER_PIO_2:
+                       case XFER_PIO_1:
+                       case XFER_PIO_0:
+                               set_indexed_reg(hwif, 0x0c + adj,
+                                               pio_timings[mode].reg0c);
+                               set_indexed_reg(hwif, 0x0d + adj,
+                                               pio_timings[mode].reg0d);
+                               set_indexed_reg(hwif, 0x13 + adj,
+                                               pio_timings[mode].reg13);
+                               break;
+                       default:
+                               printk(KERN_ERR "pdc202xx_new: "
+                                      "Unknown speed %d ignored\n", speed);
+               }
+       } else if (speed == XFER_UDMA_2) {
+               /* Set tHOLD bit to 0 if using UDMA mode 2 */
+               u8 tmp = get_indexed_reg(hwif, 0x10 + adj);
 
-       return (ide_config_drive_speed(drive, speed));
+               set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
+       }
+
+       return err;
 }
 
 /*   0    1    2    3    4    5    6   7   8
@@ -170,36 +259,42 @@ static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
        pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-       (void)pdcnew_new_tune_chipset(drive, XFER_PIO_0 + pio);
+       (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
-static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
 {
-       hwif->OUTB(0x0b, hwif->dma_vendor1);
-       return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+       return get_indexed_reg(hwif, 0x0b) & 0x04;
 }
-static int config_chipset_for_dma (ide_drive_t *drive)
+
+static int config_chipset_for_dma(ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
        ide_hwif_t *hwif        = HWIF(drive);
-       u8 speed                = -1;
-       u8 cable;
-
-       u8 ultra_66             = ((id->dma_ultra & 0x0010) ||
-                                  (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-       cable = pdcnew_new_cable_detect(hwif);
+       u8 ultra_66             = (id->dma_ultra & 0x0078) ? 1 : 0;
+       u8 cable                = pdcnew_cable_detect(hwif);
+       u8 speed;
 
        if (ultra_66 && cable) {
-               printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+               printk(KERN_WARNING "Warning: %s channel "
+                      "requires an 80-pin cable for operation.\n",
+                      hwif->channel ? "Secondary" : "Primary");
                printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
        }
 
        if (drive->media != ide_disk)
                return 0;
-       if (id->capability & 4) {       /* IORDY_EN & PREFETCH_EN */
-               hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
-               hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+
+       if (id->capability & 4) {
+               /*
+                * Set IORDY_EN & PREFETCH_EN (this seems to have
+                * NO real effect since this register is reloaded
+                * by hardware when the transfer mode is selected)
+                */
+               u8 tmp, adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+               tmp = get_indexed_reg(hwif, 0x13 + adj);
+               set_indexed_reg(hwif, 0x13 + adj, tmp | 0x03);
        }
 
        speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
@@ -211,7 +306,7 @@ static int config_chipset_for_dma (ide_drive_t *drive)
        return ide_dma_enable(drive);
 }
 
-static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct hd_driveid *id   = drive->id;
@@ -236,9 +331,9 @@ fast_ata_pio:
        return 0;
 }
 
-static int pdcnew_quirkproc (ide_drive_t *drive)
+static int pdcnew_quirkproc(ide_drive_t *drive)
 {
-       return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+       return check_in_drive_lists(drive, pdc_quirk_drives);
 }
 
 static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
@@ -255,21 +350,100 @@ static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
        return __ide_dma_timeout(drive);
 }
 
-static void pdcnew_new_reset (ide_drive_t *drive)
+static void pdcnew_reset(ide_drive_t *drive)
 {
        /*
         * Deleted this because it is redundant from the caller.
         */
-       printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+       printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n",
                HWIF(drive)->channel ? "Secondary" : "Primary");
 }
 
+/**
+ * read_counter - Read the byte count registers
+ * @dma_base: for the port address
+ */
+static long __devinit read_counter(u32 dma_base)
+{
+       u32  pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
+       u8   cnt0, cnt1, cnt2, cnt3;
+       long count = 0, last;
+       int  retry = 3;
+
+       do {
+               last = count;
+
+               /* Read the current count */
+               outb(0x20, pri_dma_base + 0x01);
+               cnt0 = inb(pri_dma_base + 0x03);
+               outb(0x21, pri_dma_base + 0x01);
+               cnt1 = inb(pri_dma_base + 0x03);
+               outb(0x20, sec_dma_base + 0x01);
+               cnt2 = inb(sec_dma_base + 0x03);
+               outb(0x21, sec_dma_base + 0x01);
+               cnt3 = inb(sec_dma_base + 0x03);
+
+               count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0;
+
+               /*
+                * The 30-bit decrementing counter is read in 4 pieces.
+                * Incorrect value may be read when the most significant bytes
+                * are changing...
+                */
+       } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count));
+
+       DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n",
+                 cnt0, cnt1, cnt2, cnt3);
+
+       return count;
+}
+
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @dma_base: for the port address
+ * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
+ */
+static long __devinit detect_pll_input_clock(unsigned long dma_base)
+{
+       long start_count, end_count;
+       long pll_input;
+       u8 scr1;
+
+       start_count = read_counter(dma_base);
+
+       /* Start the test mode */
+       outb(0x01, dma_base + 0x01);
+       scr1 = inb(dma_base + 0x03);
+       DBG("scr1[%02X]\n", scr1);
+       outb(scr1 | 0x40, dma_base + 0x03);
+
+       /* Let the counter run for 10 ms. */
+       mdelay(10);
+
+       end_count = read_counter(dma_base);
+
+       /* Stop the test mode */
+       outb(0x01, dma_base + 0x01);
+       scr1 = inb(dma_base + 0x03);
+       DBG("scr1[%02X]\n", scr1);
+       outb(scr1 & ~0x40, dma_base + 0x03);
+
+       /*
+        * Calculate the input clock in Hz
+        * (the clock counter is 30 bit wide and counts down)
+        */
+       pll_input = ((start_count - end_count) & 0x3ffffff) * 100;
+
+       DBG("start[%ld] end[%ld]\n", start_count, end_count);
+
+       return pll_input;
+}
+
 #ifdef CONFIG_PPC_PMAC
 static void __devinit apple_kiwi_init(struct pci_dev *pdev)
 {
        struct device_node *np = pci_device_to_OF_node(pdev);
        unsigned int class_rev = 0;
-       void __iomem *mmio;
        u8 conf;
 
        if (np == NULL || !device_is_compatible(np, "kiwi-root"))
@@ -280,30 +454,20 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev)
 
        if (class_rev >= 0x03) {
                /* Setup chip magic config stuff (from darwin) */
-               pci_read_config_byte(pdev, 0x40, &conf);
-               pci_write_config_byte(pdev, 0x40, conf | 0x01);
-       }
-       mmio = ioremap(pci_resource_start(pdev, 5),
-                                     pci_resource_len(pdev, 5));
-
-       /* Setup some PLL stuffs */
-       switch (pdev->device) {
-       case PCI_DEVICE_ID_PROMISE_20270:
-               writew(0x0d2b, mmio + 0x1202);
-               mdelay(30);
-               break;
-       case PCI_DEVICE_ID_PROMISE_20271:
-               writew(0x0826, mmio + 0x1202);
-               mdelay(30);
-               break;
+               pci_read_config_byte (pdev, 0x40, &conf);
+               pci_write_config_byte(pdev, 0x40, (conf | 0x01));
        }
-
-       iounmap(mmio);
 }
 #endif /* CONFIG_PPC_PMAC */
 
 static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const char *name)
 {
+       unsigned long dma_base = pci_resource_start(dev, 4);
+       unsigned long sec_dma_base = dma_base + 0x08;
+       long pll_input, pll_output, ratio;
+       int f, r;
+       u8 pll_ctl0, pll_ctl1;
+
        if (dev->resource[PCI_ROM_RESOURCE].start) {
                pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                        dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
@@ -315,6 +479,106 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
        apple_kiwi_init(dev);
 #endif
 
+       /* Calculate the required PLL output frequency */
+       switch(max_dma_rate(dev)) {
+               case 4: /* it's 133 MHz for Ultra133 chips */
+                       pll_output = 133333333;
+                       break;
+               case 3: /* and  100 MHz for Ultra100 chips */
+               default:
+                       pll_output = 100000000;
+                       break;
+       }
+
+       /*
+        * Detect PLL input clock.
+        * On some systems, where PCI bus is running at non-standard clock rate
+        * (e.g. 25 or 40 MHz), we have to adjust the cycle time.
+        * PDC20268 and newer chips employ PLL circuit to help correct timing
+        * registers setting.
+        */
+       pll_input = detect_pll_input_clock(dma_base);
+       printk("%s: PLL input clock is %ld kHz\n", name, pll_input / 1000);
+
+       /* Sanity check */
+       if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) {
+               printk(KERN_ERR "%s: Bad PLL input clock %ld Hz, giving up!\n",
+                      name, pll_input);
+               goto out;
+       }
+
+#ifdef DEBUG
+       DBG("pll_output is %ld Hz\n", pll_output);
+
+       /* Show the current clock value of PLL control register
+        * (maybe already configured by the BIOS)
+        */
+       outb(0x02, sec_dma_base + 0x01);
+       pll_ctl0 = inb(sec_dma_base + 0x03);
+       outb(0x03, sec_dma_base + 0x01);
+       pll_ctl1 = inb(sec_dma_base + 0x03);
+
+       DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+       /*
+        * Calculate the ratio of F, R and NO
+        * POUT = (F + 2) / (( R + 2) * NO)
+        */
+       ratio = pll_output / (pll_input / 1000);
+       if (ratio < 8600L) { /* 8.6x */
+               /* Using NO = 0x01, R = 0x0d */
+               r = 0x0d;
+       } else if (ratio < 12900L) { /* 12.9x */
+               /* Using NO = 0x01, R = 0x08 */
+               r = 0x08;
+       } else if (ratio < 16100L) { /* 16.1x */
+               /* Using NO = 0x01, R = 0x06 */
+               r = 0x06;
+       } else if (ratio < 64000L) { /* 64x */
+               r = 0x00;
+       } else {
+               /* Invalid ratio */
+               printk(KERN_ERR "%s: Bad ratio %ld, giving up!\n", name, ratio);
+               goto out;
+       }
+
+       f = (ratio * (r + 2)) / 1000 - 2;
+
+       DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio);
+
+       if (unlikely(f < 0 || f > 127)) {
+               /* Invalid F */
+               printk(KERN_ERR "%s: F[%d] invalid!\n", name, f);
+               goto out;
+       }
+
+       pll_ctl0 = (u8) f;
+       pll_ctl1 = (u8) r;
+
+       DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+
+       outb(0x02,     sec_dma_base + 0x01);
+       outb(pll_ctl0, sec_dma_base + 0x03);
+       outb(0x03,     sec_dma_base + 0x01);
+       outb(pll_ctl1, sec_dma_base + 0x03);
+
+       /* Wait the PLL circuit to be stable */
+       mdelay(30);
+
+#ifdef DEBUG
+       /*
+        *  Show the current clock value of PLL control register
+        */
+       outb(0x02, sec_dma_base + 0x01);
+       pll_ctl0 = inb(sec_dma_base + 0x03);
+       outb(0x03, sec_dma_base + 0x01);
+       pll_ctl1 = inb(sec_dma_base + 0x03);
+
+       DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ out:
        return dev->irq;
 }
 
@@ -324,8 +588,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
 
        hwif->tuneproc  = &pdcnew_tune_drive;
        hwif->quirkproc = &pdcnew_quirkproc;
-       hwif->speedproc = &pdcnew_new_tune_chipset;
-       hwif->resetproc = &pdcnew_new_reset;
+       hwif->speedproc = &pdcnew_tune_chipset;
+       hwif->resetproc = &pdcnew_reset;
 
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
@@ -337,11 +601,14 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
        hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
        hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
-       if (!(hwif->udma_four))
-               hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+
+       if (!hwif->udma_four)
+               hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
+
        if (!noautodma)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+
 #if PDC202_DEBUG_CABLE
        printk(KERN_DEBUG "%s: %s-pin cable\n",
                hwif->name, hwif->udma_four ? "80" : "40");
index cdc3aab9ebcbc46676c76f6e5569f13eb214505a..b1e9a8eba6b679697d9cbe6fb7e6aa38158fbcbc 100644 (file)
@@ -505,6 +505,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
                /* This is a painful system best to let it self tune for now */
                return;
        }
+       /* ESB2 appears to generate spurious DMA interrupts in PIO mode
+          when in native mode */
+       if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18)
+               hwif->atapi_irq_bogon = 1;
 
        hwif->autodma = 0;
        hwif->tuneproc = &piix_tune_drive;
index 0719b6484824cd6075923ef0b322a417a1713f47..695e23904d3030e61c4f2ba24d88740415847a07 100644 (file)
@@ -844,11 +844,11 @@ void __init ide_scan_pcibus (int scan_direction)
 
        pre_init = 0;
        if (!scan_direction) {
-               while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                        ide_scan_pcidev(dev);
                }
        } else {
-               while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
                        ide_scan_pcidev(dev);
                }
        }
index 29ca0ab0acb8a20de784853dd528b08ba9626756..3d5f19658032c9f2bbe28bf8639879cd365150de 100644 (file)
@@ -146,7 +146,7 @@ config TOUCHSCREEN_TOUCHWIN
 
 config TOUCHSCREEN_UCB1400
        tristate "Philips UCB1400 touchscreen"
-       select SND_AC97_BUS
+       depends on SND_AC97_BUS
        help
          This enables support for the Philips UCB1400 touchscreen interface.
          The UCB1400 is an AC97 audio codec.  The touchscreen interface
index 6fa12cc8e4ff858af4904f304a5ca4c1b56068ba..34ab5f7dcabc1daa4087893bde2c58c568687afa 100644 (file)
@@ -110,7 +110,7 @@ config HISAX_16_3
 
 config HISAX_TELESPCI
        bool "Teles PCI"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
        help
          This enables HiSax support for the Teles PCI.
          See <file:Documentation/isdn/README.HiSax> on how to configure it.
@@ -238,7 +238,7 @@ config HISAX_MIC
 
 config HISAX_NETJET
        bool "NETjet card"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
        help
          This enables HiSax support for the NetJet from Traverse
          Technologies.
@@ -249,7 +249,7 @@ config HISAX_NETJET
 
 config HISAX_NETJET_U
        bool "NETspider U card"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
        help
          This enables HiSax support for the Netspider U interface ISDN card
          from Traverse Technologies.
@@ -317,7 +317,7 @@ config HISAX_GAZEL
 
 config HISAX_HFC_PCI
        bool "HFC PCI-Bus cards"
-       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+       depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
        help
          This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
 
@@ -344,7 +344,7 @@ config HISAX_HFC_SX
 
 config HISAX_ENTERNOW_PCI
        bool "Formula-n enter:now PCI card"
-       depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV))
+       depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
        help
          This enables HiSax support for the Formula-n enter:now PCI
          ISDN card.
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
new file mode 100644 (file)
index 0000000..36412e9
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# KVM configuration
+#
+config KVM
+       tristate "Kernel-based Virtual Machine (KVM) support"
+       depends on X86 && EXPERIMENTAL
+       ---help---
+         Support hosting fully virtualized guest machines using hardware
+         virtualization extensions.  You will need a fairly recent
+         processor equipped with virtualization extensions. You will also
+         need to select one or more of the processor modules below.
+
+         This module provides access to the hardware capabilities through
+         a character device node named /dev/kvm.
+
+         To compile this as a module, choose M here: the module
+         will be called kvm.
+
+         If unsure, say N.
+
+config KVM_INTEL
+       tristate "KVM for Intel processors support"
+       depends on KVM
+       ---help---
+         Provides support for KVM on Intel processors equipped with the VT
+         extensions.
+
+config KVM_AMD
+       tristate "KVM for AMD processors support"
+       depends on KVM
+       ---help---
+         Provides support for KVM on AMD processors equipped with the AMD-V
+         (SVM) extensions.
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
new file mode 100644 (file)
index 0000000..c0a789f
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+kvm-objs := kvm_main.o mmu.o x86_emulate.o
+obj-$(CONFIG_KVM) += kvm.o
+kvm-intel-objs = vmx.o
+obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
+kvm-amd-objs = svm.o
+obj-$(CONFIG_KVM_AMD) += kvm-amd.o
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
new file mode 100644 (file)
index 0000000..5785d08
--- /dev/null
@@ -0,0 +1,551 @@
+#ifndef __KVM_H
+#define __KVM_H
+
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include "vmx.h"
+#include <linux/kvm.h>
+
+#define CR0_PE_MASK (1ULL << 0)
+#define CR0_TS_MASK (1ULL << 3)
+#define CR0_NE_MASK (1ULL << 5)
+#define CR0_WP_MASK (1ULL << 16)
+#define CR0_NW_MASK (1ULL << 29)
+#define CR0_CD_MASK (1ULL << 30)
+#define CR0_PG_MASK (1ULL << 31)
+
+#define CR3_WPT_MASK (1ULL << 3)
+#define CR3_PCD_MASK (1ULL << 4)
+
+#define CR3_RESEVED_BITS 0x07ULL
+#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
+#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
+
+#define CR4_VME_MASK (1ULL << 0)
+#define CR4_PSE_MASK (1ULL << 4)
+#define CR4_PAE_MASK (1ULL << 5)
+#define CR4_PGE_MASK (1ULL << 7)
+#define CR4_VMXE_MASK (1ULL << 13)
+
+#define KVM_GUEST_CR0_MASK \
+       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
+        | CR0_NW_MASK | CR0_CD_MASK)
+#define KVM_VM_CR0_ALWAYS_ON \
+       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+#define KVM_GUEST_CR4_MASK \
+       (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+
+#define INVALID_PAGE (~(hpa_t)0)
+#define UNMAPPED_GVA (~(gpa_t)0)
+
+#define KVM_MAX_VCPUS 1
+#define KVM_MEMORY_SLOTS 4
+#define KVM_NUM_MMU_PAGES 256
+
+#define FX_IMAGE_SIZE 512
+#define FX_IMAGE_ALIGN 16
+#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
+
+#define DE_VECTOR 0
+#define DF_VECTOR 8
+#define TS_VECTOR 10
+#define NP_VECTOR 11
+#define SS_VECTOR 12
+#define GP_VECTOR 13
+#define PF_VECTOR 14
+
+#define SELECTOR_TI_MASK (1 << 2)
+#define SELECTOR_RPL_MASK 0x03
+
+#define IOPL_SHIFT 12
+
+/*
+ * Address types:
+ *
+ *  gva - guest virtual address
+ *  gpa - guest physical address
+ *  gfn - guest frame number
+ *  hva - host virtual address
+ *  hpa - host physical address
+ *  hfn - host frame number
+ */
+
+typedef unsigned long  gva_t;
+typedef u64            gpa_t;
+typedef unsigned long  gfn_t;
+
+typedef unsigned long  hva_t;
+typedef u64            hpa_t;
+typedef unsigned long  hfn_t;
+
+struct kvm_mmu_page {
+       struct list_head link;
+       hpa_t page_hpa;
+       unsigned long slot_bitmap; /* One bit set per slot which has memory
+                                   * in this shadow page.
+                                   */
+       int global;              /* Set if all ptes in this page are global */
+       u64 *parent_pte;
+};
+
+struct vmcs {
+       u32 revision_id;
+       u32 abort;
+       char data[0];
+};
+
+#define vmx_msr_entry kvm_msr_entry
+
+struct kvm_vcpu;
+
+/*
+ * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
+ * 32-bit).  The kvm_mmu structure abstracts the details of the current mmu
+ * mode.
+ */
+struct kvm_mmu {
+       void (*new_cr3)(struct kvm_vcpu *vcpu);
+       int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+       void (*inval_page)(struct kvm_vcpu *vcpu, gva_t gva);
+       void (*free)(struct kvm_vcpu *vcpu);
+       gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva);
+       hpa_t root_hpa;
+       int root_level;
+       int shadow_root_level;
+};
+
+struct kvm_guest_debug {
+       int enabled;
+       unsigned long bp[4];
+       int singlestep;
+};
+
+enum {
+       VCPU_REGS_RAX = 0,
+       VCPU_REGS_RCX = 1,
+       VCPU_REGS_RDX = 2,
+       VCPU_REGS_RBX = 3,
+       VCPU_REGS_RSP = 4,
+       VCPU_REGS_RBP = 5,
+       VCPU_REGS_RSI = 6,
+       VCPU_REGS_RDI = 7,
+#ifdef __x86_64__
+       VCPU_REGS_R8 = 8,
+       VCPU_REGS_R9 = 9,
+       VCPU_REGS_R10 = 10,
+       VCPU_REGS_R11 = 11,
+       VCPU_REGS_R12 = 12,
+       VCPU_REGS_R13 = 13,
+       VCPU_REGS_R14 = 14,
+       VCPU_REGS_R15 = 15,
+#endif
+       NR_VCPU_REGS
+};
+
+enum {
+       VCPU_SREG_CS,
+       VCPU_SREG_DS,
+       VCPU_SREG_ES,
+       VCPU_SREG_FS,
+       VCPU_SREG_GS,
+       VCPU_SREG_SS,
+       VCPU_SREG_TR,
+       VCPU_SREG_LDTR,
+};
+
+struct kvm_vcpu {
+       struct kvm *kvm;
+       union {
+               struct vmcs *vmcs;
+               struct vcpu_svm *svm;
+       };
+       struct mutex mutex;
+       int   cpu;
+       int   launched;
+       unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
+#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
+       unsigned long irq_pending[NR_IRQ_WORDS];
+       unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
+       unsigned long rip;      /* needs vcpu_load_rsp_rip() */
+
+       unsigned long cr0;
+       unsigned long cr2;
+       unsigned long cr3;
+       unsigned long cr4;
+       unsigned long cr8;
+       u64 shadow_efer;
+       u64 apic_base;
+       int nmsrs;
+       struct vmx_msr_entry *guest_msrs;
+       struct vmx_msr_entry *host_msrs;
+
+       struct list_head free_pages;
+       struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES];
+       struct kvm_mmu mmu;
+
+       struct kvm_guest_debug guest_debug;
+
+       char fx_buf[FX_BUF_SIZE];
+       char *host_fx_image;
+       char *guest_fx_image;
+
+       int mmio_needed;
+       int mmio_read_completed;
+       int mmio_is_write;
+       int mmio_size;
+       unsigned char mmio_data[8];
+       gpa_t mmio_phys_addr;
+
+       struct {
+               int active;
+               u8 save_iopl;
+               struct kvm_save_segment {
+                       u16 selector;
+                       unsigned long base;
+                       u32 limit;
+                       u32 ar;
+               } tr, es, ds, fs, gs;
+       } rmode;
+};
+
+struct kvm_memory_slot {
+       gfn_t base_gfn;
+       unsigned long npages;
+       unsigned long flags;
+       struct page **phys_mem;
+       unsigned long *dirty_bitmap;
+};
+
+struct kvm {
+       spinlock_t lock; /* protects everything except vcpus */
+       int nmemslots;
+       struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS];
+       struct list_head active_mmu_pages;
+       struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
+       int memory_config_version;
+       int busy;
+};
+
+struct kvm_stat {
+       u32 pf_fixed;
+       u32 pf_guest;
+       u32 tlb_flush;
+       u32 invlpg;
+
+       u32 exits;
+       u32 io_exits;
+       u32 mmio_exits;
+       u32 signal_exits;
+       u32 irq_exits;
+};
+
+struct descriptor_table {
+       u16 limit;
+       unsigned long base;
+} __attribute__((packed));
+
+struct kvm_arch_ops {
+       int (*cpu_has_kvm_support)(void);          /* __init */
+       int (*disabled_by_bios)(void);             /* __init */
+       void (*hardware_enable)(void *dummy);      /* __init */
+       void (*hardware_disable)(void *dummy);
+       int (*hardware_setup)(void);               /* __init */
+       void (*hardware_unsetup)(void);            /* __exit */
+
+       int (*vcpu_create)(struct kvm_vcpu *vcpu);
+       void (*vcpu_free)(struct kvm_vcpu *vcpu);
+
+       struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
+       void (*vcpu_put)(struct kvm_vcpu *vcpu);
+
+       int (*set_guest_debug)(struct kvm_vcpu *vcpu,
+                              struct kvm_debug_guest *dbg);
+       int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+       int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
+       u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
+       void (*get_segment)(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg);
+       void (*set_segment)(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg);
+       int (*is_long_mode)(struct kvm_vcpu *vcpu);
+       void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
+       void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
+       void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
+                                     unsigned long cr0);
+       void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
+       void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
+       void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
+       void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+       void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+       void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+       void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
+       unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
+       void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
+                      int *exception);
+       void (*cache_regs)(struct kvm_vcpu *vcpu);
+       void (*decache_regs)(struct kvm_vcpu *vcpu);
+       unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
+       void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
+
+       void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr);
+       void (*tlb_flush)(struct kvm_vcpu *vcpu);
+       void (*inject_page_fault)(struct kvm_vcpu *vcpu,
+                                 unsigned long addr, u32 err_code);
+
+       void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
+
+       int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+       int (*vcpu_setup)(struct kvm_vcpu *vcpu);
+       void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+};
+
+extern struct kvm_stat kvm_stat;
+extern struct kvm_arch_ops *kvm_arch_ops;
+
+#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
+#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
+
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
+void kvm_exit_arch(void);
+
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
+int kvm_mmu_init(struct kvm_vcpu *vcpu);
+
+int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+
+hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
+#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
+#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
+static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
+hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
+
+void kvm_emulator_want_group7_invlpg(void);
+
+extern hpa_t bad_page_address;
+
+static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn)
+{
+       return slot->phys_mem[gfn - slot->base_gfn];
+}
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
+void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
+
+enum emulation_result {
+       EMULATE_DONE,       /* no further processing */
+       EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
+       EMULATE_FAIL,         /* can't emulate this instruction */
+};
+
+int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+                       unsigned long cr2, u16 error_code);
+void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
+void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
+                  unsigned long *rflags);
+
+unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
+                    unsigned long *rflags);
+
+struct x86_emulate_ctxt;
+
+int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
+int emulate_clts(struct kvm_vcpu *vcpu);
+int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
+                   unsigned long *dest);
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
+                   unsigned long value);
+
+void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
+void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+
+#ifdef __x86_64__
+void set_efer(struct kvm_vcpu *vcpu, u64 efer);
+#endif
+
+void fx_init(struct kvm_vcpu *vcpu);
+
+void load_msrs(struct vmx_msr_entry *e, int n);
+void save_msrs(struct vmx_msr_entry *e, int n);
+void kvm_resched(struct kvm_vcpu *vcpu);
+
+int kvm_read_guest(struct kvm_vcpu *vcpu,
+              gva_t addr,
+              unsigned long size,
+              void *dest);
+
+int kvm_write_guest(struct kvm_vcpu *vcpu,
+               gva_t addr,
+               unsigned long size,
+               void *data);
+
+unsigned long segment_base(u16 selector);
+
+static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+       struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+       return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL;
+}
+
+static inline int is_pae(struct kvm_vcpu *vcpu)
+{
+       return vcpu->cr4 & CR4_PAE_MASK;
+}
+
+static inline int is_pse(struct kvm_vcpu *vcpu)
+{
+       return vcpu->cr4 & CR4_PSE_MASK;
+}
+
+static inline int is_paging(struct kvm_vcpu *vcpu)
+{
+       return vcpu->cr0 & CR0_PG_MASK;
+}
+
+static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+       return slot - kvm->memslots;
+}
+
+static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
+{
+       struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
+
+       return (struct kvm_mmu_page *)page->private;
+}
+
+static inline u16 read_fs(void)
+{
+       u16 seg;
+       asm ("mov %%fs, %0" : "=g"(seg));
+       return seg;
+}
+
+static inline u16 read_gs(void)
+{
+       u16 seg;
+       asm ("mov %%gs, %0" : "=g"(seg));
+       return seg;
+}
+
+static inline u16 read_ldt(void)
+{
+       u16 ldt;
+       asm ("sldt %0" : "=g"(ldt));
+       return ldt;
+}
+
+static inline void load_fs(u16 sel)
+{
+       asm ("mov %0, %%fs" : : "rm"(sel));
+}
+
+static inline void load_gs(u16 sel)
+{
+       asm ("mov %0, %%gs" : : "rm"(sel));
+}
+
+#ifndef load_ldt
+static inline void load_ldt(u16 sel)
+{
+       asm ("lldt %0" : : "g"(sel));
+}
+#endif
+
+static inline void get_idt(struct descriptor_table *table)
+{
+       asm ("sidt %0" : "=m"(*table));
+}
+
+static inline void get_gdt(struct descriptor_table *table)
+{
+       asm ("sgdt %0" : "=m"(*table));
+}
+
+static inline unsigned long read_tr_base(void)
+{
+       u16 tr;
+       asm ("str %0" : "=g"(tr));
+       return segment_base(tr);
+}
+
+#ifdef __x86_64__
+static inline unsigned long read_msr(unsigned long msr)
+{
+       u64 value;
+
+       rdmsrl(msr, value);
+       return value;
+}
+#endif
+
+static inline void fx_save(void *image)
+{
+       asm ("fxsave (%0)":: "r" (image));
+}
+
+static inline void fx_restore(void *image)
+{
+       asm ("fxrstor (%0)":: "r" (image));
+}
+
+static inline void fpu_init(void)
+{
+       asm ("finit");
+}
+
+static inline u32 get_rdx_init_val(void)
+{
+       return 0x600; /* P6 family */
+}
+
+#define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
+#define ASM_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
+#define ASM_VMX_VMPTRLD_RAX       ".byte 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMREAD_RDX_RAX    ".byte 0x0f, 0x78, 0xd0"
+#define ASM_VMX_VMWRITE_RAX_RDX   ".byte 0x0f, 0x79, 0xd0"
+#define ASM_VMX_VMWRITE_RSP_RDX   ".byte 0x0f, 0x79, 0xd4"
+#define ASM_VMX_VMXOFF            ".byte 0x0f, 0x01, 0xc4"
+#define ASM_VMX_VMXON_RAX         ".byte 0xf3, 0x0f, 0xc7, 0x30"
+
+#define MSR_IA32_TIME_STAMP_COUNTER            0x010
+
+#define TSS_IOPB_BASE_OFFSET 0x66
+#define TSS_BASE_SIZE 0x68
+#define TSS_IOPB_SIZE (65536 / 8)
+#define TSS_REDIRECTION_SIZE (256 / 8)
+#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
+
+#ifdef __x86_64__
+
+/*
+ * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.  Therefore
+ * we need to allocate shadow page tables in the first 4GB of memory, which
+ * happens to fit the DMA32 zone.
+ */
+#define GFP_KVM_MMU (GFP_KERNEL | __GFP_DMA32)
+
+#else
+
+#define GFP_KVM_MMU GFP_KERNEL
+
+#endif
+
+#endif
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
new file mode 100644 (file)
index 0000000..b6b8a41
--- /dev/null
@@ -0,0 +1,1935 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Avi Kivity   <avi@qumranet.com>
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "kvm.h"
+
+#include <linux/kvm.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/processor.h>
+#include <linux/percpu.h>
+#include <linux/gfp.h>
+#include <asm/msr.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+#include <linux/debugfs.h>
+#include <linux/highmem.h>
+#include <linux/file.h>
+#include <asm/desc.h>
+
+#include "x86_emulate.h"
+#include "segment_descriptor.h"
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+struct kvm_arch_ops *kvm_arch_ops;
+struct kvm_stat kvm_stat;
+EXPORT_SYMBOL_GPL(kvm_stat);
+
+static struct kvm_stats_debugfs_item {
+       const char *name;
+       u32 *data;
+       struct dentry *dentry;
+} debugfs_entries[] = {
+       { "pf_fixed", &kvm_stat.pf_fixed },
+       { "pf_guest", &kvm_stat.pf_guest },
+       { "tlb_flush", &kvm_stat.tlb_flush },
+       { "invlpg", &kvm_stat.invlpg },
+       { "exits", &kvm_stat.exits },
+       { "io_exits", &kvm_stat.io_exits },
+       { "mmio_exits", &kvm_stat.mmio_exits },
+       { "signal_exits", &kvm_stat.signal_exits },
+       { "irq_exits", &kvm_stat.irq_exits },
+       { 0, 0 }
+};
+
+static struct dentry *debugfs_dir;
+
+#define MAX_IO_MSRS 256
+
+#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
+#define LMSW_GUEST_MASK 0x0eULL
+#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
+#define CR8_RESEVED_BITS (~0x0fULL)
+#define EFER_RESERVED_BITS 0xfffffffffffff2fe
+
+struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+{
+       int i;
+
+       for (i = 0; i < vcpu->nmsrs; ++i)
+               if (vcpu->guest_msrs[i].index == msr)
+                       return &vcpu->guest_msrs[i];
+       return 0;
+}
+EXPORT_SYMBOL_GPL(find_msr_entry);
+
+#ifdef __x86_64__
+// LDT or TSS descriptor in the GDT. 16 bytes.
+struct segment_descriptor_64 {
+       struct segment_descriptor s;
+       u32 base_higher;
+       u32 pad_zero;
+};
+
+#endif
+
+unsigned long segment_base(u16 selector)
+{
+       struct descriptor_table gdt;
+       struct segment_descriptor *d;
+       unsigned long table_base;
+       typedef unsigned long ul;
+       unsigned long v;
+
+       if (selector == 0)
+               return 0;
+
+       asm ("sgdt %0" : "=m"(gdt));
+       table_base = gdt.base;
+
+       if (selector & 4) {           /* from ldt */
+               u16 ldt_selector;
+
+               asm ("sldt %0" : "=g"(ldt_selector));
+               table_base = segment_base(ldt_selector);
+       }
+       d = (struct segment_descriptor *)(table_base + (selector & ~7));
+       v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24);
+#ifdef __x86_64__
+       if (d->system == 0
+           && (d->type == 2 || d->type == 9 || d->type == 11))
+               v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32;
+#endif
+       return v;
+}
+EXPORT_SYMBOL_GPL(segment_base);
+
+int kvm_read_guest(struct kvm_vcpu *vcpu,
+                            gva_t addr,
+                            unsigned long size,
+                            void *dest)
+{
+       unsigned char *host_buf = dest;
+       unsigned long req_size = size;
+
+       while (size) {
+               hpa_t paddr;
+               unsigned now;
+               unsigned offset;
+               hva_t guest_buf;
+
+               paddr = gva_to_hpa(vcpu, addr);
+
+               if (is_error_hpa(paddr))
+                       break;
+
+               guest_buf = (hva_t)kmap_atomic(
+                                       pfn_to_page(paddr >> PAGE_SHIFT),
+                                       KM_USER0);
+               offset = addr & ~PAGE_MASK;
+               guest_buf |= offset;
+               now = min(size, PAGE_SIZE - offset);
+               memcpy(host_buf, (void*)guest_buf, now);
+               host_buf += now;
+               addr += now;
+               size -= now;
+               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
+       }
+       return req_size - size;
+}
+EXPORT_SYMBOL_GPL(kvm_read_guest);
+
+int kvm_write_guest(struct kvm_vcpu *vcpu,
+                            gva_t addr,
+                            unsigned long size,
+                            void *data)
+{
+       unsigned char *host_buf = data;
+       unsigned long req_size = size;
+
+       while (size) {
+               hpa_t paddr;
+               unsigned now;
+               unsigned offset;
+               hva_t guest_buf;
+
+               paddr = gva_to_hpa(vcpu, addr);
+
+               if (is_error_hpa(paddr))
+                       break;
+
+               guest_buf = (hva_t)kmap_atomic(
+                               pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
+               offset = addr & ~PAGE_MASK;
+               guest_buf |= offset;
+               now = min(size, PAGE_SIZE - offset);
+               memcpy((void*)guest_buf, host_buf, now);
+               host_buf += now;
+               addr += now;
+               size -= now;
+               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
+       }
+       return req_size - size;
+}
+EXPORT_SYMBOL_GPL(kvm_write_guest);
+
+static int vcpu_slot(struct kvm_vcpu *vcpu)
+{
+       return vcpu - vcpu->kvm->vcpus;
+}
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put()
+ */
+static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
+{
+       struct kvm_vcpu *vcpu = &kvm->vcpus[vcpu_slot];
+
+       mutex_lock(&vcpu->mutex);
+       if (unlikely(!vcpu->vmcs)) {
+               mutex_unlock(&vcpu->mutex);
+               return 0;
+       }
+       return kvm_arch_ops->vcpu_load(vcpu);
+}
+
+static void vcpu_put(struct kvm_vcpu *vcpu)
+{
+       kvm_arch_ops->vcpu_put(vcpu);
+       put_cpu();
+       mutex_unlock(&vcpu->mutex);
+}
+
+static int kvm_dev_open(struct inode *inode, struct file *filp)
+{
+       struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+       int i;
+
+       if (!kvm)
+               return -ENOMEM;
+
+       spin_lock_init(&kvm->lock);
+       INIT_LIST_HEAD(&kvm->active_mmu_pages);
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               struct kvm_vcpu *vcpu = &kvm->vcpus[i];
+
+               mutex_init(&vcpu->mutex);
+               vcpu->mmu.root_hpa = INVALID_PAGE;
+               INIT_LIST_HEAD(&vcpu->free_pages);
+       }
+       filp->private_data = kvm;
+       return 0;
+}
+
+/*
+ * Free any memory in @free but not in @dont.
+ */
+static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
+                                 struct kvm_memory_slot *dont)
+{
+       int i;
+
+       if (!dont || free->phys_mem != dont->phys_mem)
+               if (free->phys_mem) {
+                       for (i = 0; i < free->npages; ++i)
+                               __free_page(free->phys_mem[i]);
+                       vfree(free->phys_mem);
+               }
+
+       if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
+               vfree(free->dirty_bitmap);
+
+       free->phys_mem = 0;
+       free->npages = 0;
+       free->dirty_bitmap = 0;
+}
+
+static void kvm_free_physmem(struct kvm *kvm)
+{
+       int i;
+
+       for (i = 0; i < kvm->nmemslots; ++i)
+               kvm_free_physmem_slot(&kvm->memslots[i], 0);
+}
+
+static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
+{
+       kvm_arch_ops->vcpu_free(vcpu);
+       kvm_mmu_destroy(vcpu);
+}
+
+static void kvm_free_vcpus(struct kvm *kvm)
+{
+       unsigned int i;
+
+       for (i = 0; i < KVM_MAX_VCPUS; ++i)
+               kvm_free_vcpu(&kvm->vcpus[i]);
+}
+
+static int kvm_dev_release(struct inode *inode, struct file *filp)
+{
+       struct kvm *kvm = filp->private_data;
+
+       kvm_free_vcpus(kvm);
+       kvm_free_physmem(kvm);
+       kfree(kvm);
+       return 0;
+}
+
+static void inject_gp(struct kvm_vcpu *vcpu)
+{
+       kvm_arch_ops->inject_gp(vcpu, 0);
+}
+
+static int pdptrs_have_reserved_bits_set(struct kvm_vcpu *vcpu,
+                                        unsigned long cr3)
+{
+       gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
+       unsigned offset = (cr3 & (PAGE_SIZE-1)) >> 5;
+       int i;
+       u64 pdpte;
+       u64 *pdpt;
+       struct kvm_memory_slot *memslot;
+
+       spin_lock(&vcpu->kvm->lock);
+       memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn);
+       /* FIXME: !memslot - emulate? 0xff? */
+       pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0);
+
+       for (i = 0; i < 4; ++i) {
+               pdpte = pdpt[offset + i];
+               if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull))
+                       break;
+       }
+
+       kunmap_atomic(pdpt, KM_USER0);
+       spin_unlock(&vcpu->kvm->lock);
+
+       return i != 4;
+}
+
+void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+       if (cr0 & CR0_RESEVED_BITS) {
+               printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
+                      cr0, vcpu->cr0);
+               inject_gp(vcpu);
+               return;
+       }
+
+       if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+               printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
+               inject_gp(vcpu);
+               return;
+       }
+
+       if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+               printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
+                      "and a clear PE flag\n");
+               inject_gp(vcpu);
+               return;
+       }
+
+       if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+#ifdef __x86_64__
+               if ((vcpu->shadow_efer & EFER_LME)) {
+                       int cs_db, cs_l;
+
+                       if (!is_pae(vcpu)) {
+                               printk(KERN_DEBUG "set_cr0: #GP, start paging "
+                                      "in long mode while PAE is disabled\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
+                       kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+                       if (cs_l) {
+                               printk(KERN_DEBUG "set_cr0: #GP, start paging "
+                                      "in long mode while CS.L == 1\n");
+                               inject_gp(vcpu);
+                               return;
+
+                       }
+               } else
+#endif
+               if (is_pae(vcpu) &&
+                           pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
+                       printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
+                              "reserved bits\n");
+                       inject_gp(vcpu);
+                       return;
+               }
+
+       }
+
+       kvm_arch_ops->set_cr0(vcpu, cr0);
+       vcpu->cr0 = cr0;
+
+       spin_lock(&vcpu->kvm->lock);
+       kvm_mmu_reset_context(vcpu);
+       spin_unlock(&vcpu->kvm->lock);
+       return;
+}
+EXPORT_SYMBOL_GPL(set_cr0);
+
+void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
+{
+       set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
+}
+EXPORT_SYMBOL_GPL(lmsw);
+
+void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+       if (cr4 & CR4_RESEVED_BITS) {
+               printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
+               inject_gp(vcpu);
+               return;
+       }
+
+       if (kvm_arch_ops->is_long_mode(vcpu)) {
+               if (!(cr4 & CR4_PAE_MASK)) {
+                       printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
+                              "in long mode\n");
+                       inject_gp(vcpu);
+                       return;
+               }
+       } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+                  && pdptrs_have_reserved_bits_set(vcpu, vcpu->cr3)) {
+               printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
+               inject_gp(vcpu);
+       }
+
+       if (cr4 & CR4_VMXE_MASK) {
+               printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
+               inject_gp(vcpu);
+               return;
+       }
+       kvm_arch_ops->set_cr4(vcpu, cr4);
+       spin_lock(&vcpu->kvm->lock);
+       kvm_mmu_reset_context(vcpu);
+       spin_unlock(&vcpu->kvm->lock);
+}
+EXPORT_SYMBOL_GPL(set_cr4);
+
+void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+       if (kvm_arch_ops->is_long_mode(vcpu)) {
+               if ( cr3 & CR3_L_MODE_RESEVED_BITS) {
+                       printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
+                       inject_gp(vcpu);
+                       return;
+               }
+       } else {
+               if (cr3 & CR3_RESEVED_BITS) {
+                       printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
+                       inject_gp(vcpu);
+                       return;
+               }
+               if (is_paging(vcpu) && is_pae(vcpu) &&
+                   pdptrs_have_reserved_bits_set(vcpu, cr3)) {
+                       printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+                              "reserved bits\n");
+                       inject_gp(vcpu);
+                       return;
+               }
+       }
+
+       vcpu->cr3 = cr3;
+       spin_lock(&vcpu->kvm->lock);
+       vcpu->mmu.new_cr3(vcpu);
+       spin_unlock(&vcpu->kvm->lock);
+}
+EXPORT_SYMBOL_GPL(set_cr3);
+
+void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+       if ( cr8 & CR8_RESEVED_BITS) {
+               printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
+               inject_gp(vcpu);
+               return;
+       }
+       vcpu->cr8 = cr8;
+}
+EXPORT_SYMBOL_GPL(set_cr8);
+
+void fx_init(struct kvm_vcpu *vcpu)
+{
+       struct __attribute__ ((__packed__)) fx_image_s {
+               u16 control; //fcw
+               u16 status; //fsw
+               u16 tag; // ftw
+               u16 opcode; //fop
+               u64 ip; // fpu ip
+               u64 operand;// fpu dp
+               u32 mxcsr;
+               u32 mxcsr_mask;
+
+       } *fx_image;
+
+       fx_save(vcpu->host_fx_image);
+       fpu_init();
+       fx_save(vcpu->guest_fx_image);
+       fx_restore(vcpu->host_fx_image);
+
+       fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
+       fx_image->mxcsr = 0x1f80;
+       memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
+              0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+}
+EXPORT_SYMBOL_GPL(fx_init);
+
+/*
+ * Creates some virtual cpus.  Good luck creating more than one.
+ */
+static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
+{
+       int r;
+       struct kvm_vcpu *vcpu;
+
+       r = -EINVAL;
+       if (n < 0 || n >= KVM_MAX_VCPUS)
+               goto out;
+
+       vcpu = &kvm->vcpus[n];
+
+       mutex_lock(&vcpu->mutex);
+
+       if (vcpu->vmcs) {
+               mutex_unlock(&vcpu->mutex);
+               return -EEXIST;
+       }
+
+       vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
+                                          FX_IMAGE_ALIGN);
+       vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+
+       vcpu->cpu = -1;  /* First load will set up TR */
+       vcpu->kvm = kvm;
+       r = kvm_arch_ops->vcpu_create(vcpu);
+       if (r < 0)
+               goto out_free_vcpus;
+
+       kvm_arch_ops->vcpu_load(vcpu);
+
+       r = kvm_arch_ops->vcpu_setup(vcpu);
+       if (r >= 0)
+               r = kvm_mmu_init(vcpu);
+
+       vcpu_put(vcpu);
+
+       if (r < 0)
+               goto out_free_vcpus;
+
+       return 0;
+
+out_free_vcpus:
+       kvm_free_vcpu(vcpu);
+       mutex_unlock(&vcpu->mutex);
+out:
+       return r;
+}
+
+/*
+ * Allocate some memory and give it an address in the guest physical address
+ * space.
+ *
+ * Discontiguous memory is allowed, mostly for framebuffers.
+ */
+static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm,
+                                          struct kvm_memory_region *mem)
+{
+       int r;
+       gfn_t base_gfn;
+       unsigned long npages;
+       unsigned long i;
+       struct kvm_memory_slot *memslot;
+       struct kvm_memory_slot old, new;
+       int memory_config_version;
+
+       r = -EINVAL;
+       /* General sanity checks */
+       if (mem->memory_size & (PAGE_SIZE - 1))
+               goto out;
+       if (mem->guest_phys_addr & (PAGE_SIZE - 1))
+               goto out;
+       if (mem->slot >= KVM_MEMORY_SLOTS)
+               goto out;
+       if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
+               goto out;
+
+       memslot = &kvm->memslots[mem->slot];
+       base_gfn = mem->guest_phys_addr >> PAGE_SHIFT;
+       npages = mem->memory_size >> PAGE_SHIFT;
+
+       if (!npages)
+               mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
+
+raced:
+       spin_lock(&kvm->lock);
+
+       memory_config_version = kvm->memory_config_version;
+       new = old = *memslot;
+
+       new.base_gfn = base_gfn;
+       new.npages = npages;
+       new.flags = mem->flags;
+
+       /* Disallow changing a memory slot's size. */
+       r = -EINVAL;
+       if (npages && old.npages && npages != old.npages)
+               goto out_unlock;
+
+       /* Check for overlaps */
+       r = -EEXIST;
+       for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
+               struct kvm_memory_slot *s = &kvm->memslots[i];
+
+               if (s == memslot)
+                       continue;
+               if (!((base_gfn + npages <= s->base_gfn) ||
+                     (base_gfn >= s->base_gfn + s->npages)))
+                       goto out_unlock;
+       }
+       /*
+        * Do memory allocations outside lock.  memory_config_version will
+        * detect any races.
+        */
+       spin_unlock(&kvm->lock);
+
+       /* Deallocate if slot is being removed */
+       if (!npages)
+               new.phys_mem = 0;
+
+       /* Free page dirty bitmap if unneeded */
+       if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
+               new.dirty_bitmap = 0;
+
+       r = -ENOMEM;
+
+       /* Allocate if a slot is being created */
+       if (npages && !new.phys_mem) {
+               new.phys_mem = vmalloc(npages * sizeof(struct page *));
+
+               if (!new.phys_mem)
+                       goto out_free;
+
+               memset(new.phys_mem, 0, npages * sizeof(struct page *));
+               for (i = 0; i < npages; ++i) {
+                       new.phys_mem[i] = alloc_page(GFP_HIGHUSER
+                                                    | __GFP_ZERO);
+                       if (!new.phys_mem[i])
+                               goto out_free;
+               }
+       }
+
+       /* Allocate page dirty bitmap if needed */
+       if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
+               unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
+
+               new.dirty_bitmap = vmalloc(dirty_bytes);
+               if (!new.dirty_bitmap)
+                       goto out_free;
+               memset(new.dirty_bitmap, 0, dirty_bytes);
+       }
+
+       spin_lock(&kvm->lock);
+
+       if (memory_config_version != kvm->memory_config_version) {
+               spin_unlock(&kvm->lock);
+               kvm_free_physmem_slot(&new, &old);
+               goto raced;
+       }
+
+       r = -EAGAIN;
+       if (kvm->busy)
+               goto out_unlock;
+
+       if (mem->slot >= kvm->nmemslots)
+               kvm->nmemslots = mem->slot + 1;
+
+       *memslot = new;
+       ++kvm->memory_config_version;
+
+       spin_unlock(&kvm->lock);
+
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               struct kvm_vcpu *vcpu;
+
+               vcpu = vcpu_load(kvm, i);
+               if (!vcpu)
+                       continue;
+               kvm_mmu_reset_context(vcpu);
+               vcpu_put(vcpu);
+       }
+
+       kvm_free_physmem_slot(&old, &new);
+       return 0;
+
+out_unlock:
+       spin_unlock(&kvm->lock);
+out_free:
+       kvm_free_physmem_slot(&new, &old);
+out:
+       return r;
+}
+
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm,
+                                      struct kvm_dirty_log *log)
+{
+       struct kvm_memory_slot *memslot;
+       int r, i;
+       int n;
+       unsigned long any = 0;
+
+       spin_lock(&kvm->lock);
+
+       /*
+        * Prevent changes to guest memory configuration even while the lock
+        * is not taken.
+        */
+       ++kvm->busy;
+       spin_unlock(&kvm->lock);
+       r = -EINVAL;
+       if (log->slot >= KVM_MEMORY_SLOTS)
+               goto out;
+
+       memslot = &kvm->memslots[log->slot];
+       r = -ENOENT;
+       if (!memslot->dirty_bitmap)
+               goto out;
+
+       n = ALIGN(memslot->npages, 8) / 8;
+
+       for (i = 0; !any && i < n; ++i)
+               any = memslot->dirty_bitmap[i];
+
+       r = -EFAULT;
+       if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
+               goto out;
+
+
+       if (any) {
+               spin_lock(&kvm->lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->lock);
+               memset(memslot->dirty_bitmap, 0, n);
+               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+                       struct kvm_vcpu *vcpu = vcpu_load(kvm, i);
+
+                       if (!vcpu)
+                               continue;
+                       kvm_arch_ops->tlb_flush(vcpu);
+                       vcpu_put(vcpu);
+               }
+       }
+
+       r = 0;
+
+out:
+       spin_lock(&kvm->lock);
+       --kvm->busy;
+       spin_unlock(&kvm->lock);
+       return r;
+}
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+{
+       int i;
+
+       for (i = 0; i < kvm->nmemslots; ++i) {
+               struct kvm_memory_slot *memslot = &kvm->memslots[i];
+
+               if (gfn >= memslot->base_gfn
+                   && gfn < memslot->base_gfn + memslot->npages)
+                       return memslot;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gfn_to_memslot);
+
+void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
+{
+       int i;
+       struct kvm_memory_slot *memslot = 0;
+       unsigned long rel_gfn;
+
+       for (i = 0; i < kvm->nmemslots; ++i) {
+               memslot = &kvm->memslots[i];
+
+               if (gfn >= memslot->base_gfn
+                   && gfn < memslot->base_gfn + memslot->npages) {
+
+                       if (!memslot || !memslot->dirty_bitmap)
+                               return;
+
+                       rel_gfn = gfn - memslot->base_gfn;
+
+                       /* avoid RMW */
+                       if (!test_bit(rel_gfn, memslot->dirty_bitmap))
+                               set_bit(rel_gfn, memslot->dirty_bitmap);
+                       return;
+               }
+       }
+}
+
+static int emulator_read_std(unsigned long addr,
+                            unsigned long *val,
+                            unsigned int bytes,
+                            struct x86_emulate_ctxt *ctxt)
+{
+       struct kvm_vcpu *vcpu = ctxt->vcpu;
+       void *data = val;
+
+       while (bytes) {
+               gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+               unsigned offset = addr & (PAGE_SIZE-1);
+               unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
+               unsigned long pfn;
+               struct kvm_memory_slot *memslot;
+               void *page;
+
+               if (gpa == UNMAPPED_GVA)
+                       return X86EMUL_PROPAGATE_FAULT;
+               pfn = gpa >> PAGE_SHIFT;
+               memslot = gfn_to_memslot(vcpu->kvm, pfn);
+               if (!memslot)
+                       return X86EMUL_UNHANDLEABLE;
+               page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0);
+
+               memcpy(data, page + offset, tocopy);
+
+               kunmap_atomic(page, KM_USER0);
+
+               bytes -= tocopy;
+               data += tocopy;
+               addr += tocopy;
+       }
+
+       return X86EMUL_CONTINUE;
+}
+
+static int emulator_write_std(unsigned long addr,
+                             unsigned long val,
+                             unsigned int bytes,
+                             struct x86_emulate_ctxt *ctxt)
+{
+       printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
+              addr, bytes);
+       return X86EMUL_UNHANDLEABLE;
+}
+
+static int emulator_read_emulated(unsigned long addr,
+                                 unsigned long *val,
+                                 unsigned int bytes,
+                                 struct x86_emulate_ctxt *ctxt)
+{
+       struct kvm_vcpu *vcpu = ctxt->vcpu;
+
+       if (vcpu->mmio_read_completed) {
+               memcpy(val, vcpu->mmio_data, bytes);
+               vcpu->mmio_read_completed = 0;
+               return X86EMUL_CONTINUE;
+       } else if (emulator_read_std(addr, val, bytes, ctxt)
+                  == X86EMUL_CONTINUE)
+               return X86EMUL_CONTINUE;
+       else {
+               gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+               if (gpa == UNMAPPED_GVA)
+                       return vcpu_printf(vcpu, "not present\n"), X86EMUL_PROPAGATE_FAULT;
+               vcpu->mmio_needed = 1;
+               vcpu->mmio_phys_addr = gpa;
+               vcpu->mmio_size = bytes;
+               vcpu->mmio_is_write = 0;
+
+               return X86EMUL_UNHANDLEABLE;
+       }
+}
+
+static int emulator_write_emulated(unsigned long addr,
+                                  unsigned long val,
+                                  unsigned int bytes,
+                                  struct x86_emulate_ctxt *ctxt)
+{
+       struct kvm_vcpu *vcpu = ctxt->vcpu;
+       gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+
+       if (gpa == UNMAPPED_GVA)
+               return X86EMUL_PROPAGATE_FAULT;
+
+       vcpu->mmio_needed = 1;
+       vcpu->mmio_phys_addr = gpa;
+       vcpu->mmio_size = bytes;
+       vcpu->mmio_is_write = 1;
+       memcpy(vcpu->mmio_data, &val, bytes);
+
+       return X86EMUL_CONTINUE;
+}
+
+static int emulator_cmpxchg_emulated(unsigned long addr,
+                                    unsigned long old,
+                                    unsigned long new,
+                                    unsigned int bytes,
+                                    struct x86_emulate_ctxt *ctxt)
+{
+       static int reported;
+
+       if (!reported) {
+               reported = 1;
+               printk(KERN_WARNING "kvm: emulating exchange as write\n");
+       }
+       return emulator_write_emulated(addr, new, bytes, ctxt);
+}
+
+static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+       return kvm_arch_ops->get_segment_base(vcpu, seg);
+}
+
+int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
+{
+       spin_lock(&vcpu->kvm->lock);
+       vcpu->mmu.inval_page(vcpu, address);
+       spin_unlock(&vcpu->kvm->lock);
+       kvm_arch_ops->invlpg(vcpu, address);
+       return X86EMUL_CONTINUE;
+}
+
+int emulate_clts(struct kvm_vcpu *vcpu)
+{
+       unsigned long cr0 = vcpu->cr0;
+
+       cr0 &= ~CR0_TS_MASK;
+       kvm_arch_ops->set_cr0(vcpu, cr0);
+       return X86EMUL_CONTINUE;
+}
+
+int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
+{
+       struct kvm_vcpu *vcpu = ctxt->vcpu;
+
+       switch (dr) {
+       case 0 ... 3:
+               *dest = kvm_arch_ops->get_dr(vcpu, dr);
+               return X86EMUL_CONTINUE;
+       default:
+               printk(KERN_DEBUG "%s: unexpected dr %u\n",
+                      __FUNCTION__, dr);
+               return X86EMUL_UNHANDLEABLE;
+       }
+}
+
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
+{
+       unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
+       int exception;
+
+       kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
+       if (exception) {
+               /* FIXME: better handling */
+               return X86EMUL_UNHANDLEABLE;
+       }
+       return X86EMUL_CONTINUE;
+}
+
+static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
+{
+       static int reported;
+       u8 opcodes[4];
+       unsigned long rip = ctxt->vcpu->rip;
+       unsigned long rip_linear;
+
+       rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
+
+       if (reported)
+               return;
+
+       emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+
+       printk(KERN_ERR "emulation failed but !mmio_needed?"
+              " rip %lx %02x %02x %02x %02x\n",
+              rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+       reported = 1;
+}
+
+struct x86_emulate_ops emulate_ops = {
+       .read_std            = emulator_read_std,
+       .write_std           = emulator_write_std,
+       .read_emulated       = emulator_read_emulated,
+       .write_emulated      = emulator_write_emulated,
+       .cmpxchg_emulated    = emulator_cmpxchg_emulated,
+};
+
+int emulate_instruction(struct kvm_vcpu *vcpu,
+                       struct kvm_run *run,
+                       unsigned long cr2,
+                       u16 error_code)
+{
+       struct x86_emulate_ctxt emulate_ctxt;
+       int r;
+       int cs_db, cs_l;
+
+       kvm_arch_ops->cache_regs(vcpu);
+
+       kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+
+       emulate_ctxt.vcpu = vcpu;
+       emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
+       emulate_ctxt.cr2 = cr2;
+       emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
+               ? X86EMUL_MODE_REAL : cs_l
+               ? X86EMUL_MODE_PROT64 : cs_db
+               ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+
+       if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
+               emulate_ctxt.cs_base = 0;
+               emulate_ctxt.ds_base = 0;
+               emulate_ctxt.es_base = 0;
+               emulate_ctxt.ss_base = 0;
+       } else {
+               emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS);
+               emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS);
+               emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES);
+               emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS);
+       }
+
+       emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS);
+       emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
+
+       vcpu->mmio_is_write = 0;
+       r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
+
+       if ((r || vcpu->mmio_is_write) && run) {
+               run->mmio.phys_addr = vcpu->mmio_phys_addr;
+               memcpy(run->mmio.data, vcpu->mmio_data, 8);
+               run->mmio.len = vcpu->mmio_size;
+               run->mmio.is_write = vcpu->mmio_is_write;
+       }
+
+       if (r) {
+               if (!vcpu->mmio_needed) {
+                       report_emulation_failure(&emulate_ctxt);
+                       return EMULATE_FAIL;
+               }
+               return EMULATE_DO_MMIO;
+       }
+
+       kvm_arch_ops->decache_regs(vcpu);
+       kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
+
+       if (vcpu->mmio_is_write)
+               return EMULATE_DO_MMIO;
+
+       return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(emulate_instruction);
+
+static u64 mk_cr_64(u64 curr_cr, u32 new_val)
+{
+       return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
+}
+
+void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
+{
+       struct descriptor_table dt = { limit, base };
+
+       kvm_arch_ops->set_gdt(vcpu, &dt);
+}
+
+void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
+{
+       struct descriptor_table dt = { limit, base };
+
+       kvm_arch_ops->set_idt(vcpu, &dt);
+}
+
+void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
+                  unsigned long *rflags)
+{
+       lmsw(vcpu, msw);
+       *rflags = kvm_arch_ops->get_rflags(vcpu);
+}
+
+unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
+{
+       switch (cr) {
+       case 0:
+               return vcpu->cr0;
+       case 2:
+               return vcpu->cr2;
+       case 3:
+               return vcpu->cr3;
+       case 4:
+               return vcpu->cr4;
+       default:
+               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+               return 0;
+       }
+}
+
+void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
+                    unsigned long *rflags)
+{
+       switch (cr) {
+       case 0:
+               set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
+               *rflags = kvm_arch_ops->get_rflags(vcpu);
+               break;
+       case 2:
+               vcpu->cr2 = val;
+               break;
+       case 3:
+               set_cr3(vcpu, val);
+               break;
+       case 4:
+               set_cr4(vcpu, mk_cr_64(vcpu->cr4, val));
+               break;
+       default:
+               vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
+       }
+}
+
+/*
+ * Reads an msr value (of 'msr_index') into 'pdata'.
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+{
+       return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
+}
+
+#ifdef __x86_64__
+
+void set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+       struct vmx_msr_entry *msr;
+
+       if (efer & EFER_RESERVED_BITS) {
+               printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
+                      efer);
+               inject_gp(vcpu);
+               return;
+       }
+
+       if (is_paging(vcpu)
+           && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) {
+               printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
+               inject_gp(vcpu);
+               return;
+       }
+
+       efer &= ~EFER_LMA;
+       efer |= vcpu->shadow_efer & EFER_LMA;
+
+       vcpu->shadow_efer = efer;
+
+       msr = find_msr_entry(vcpu, MSR_EFER);
+
+       if (!(efer & EFER_LMA))
+           efer &= ~EFER_LME;
+       msr->data = efer;
+}
+EXPORT_SYMBOL_GPL(set_efer);
+
+#endif
+
+/*
+ * Writes msr value into into the appropriate "register".
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+{
+       return kvm_arch_ops->set_msr(vcpu, msr_index, data);
+}
+
+void kvm_resched(struct kvm_vcpu *vcpu)
+{
+       vcpu_put(vcpu);
+       cond_resched();
+       /* Cannot fail -  no vcpu unplug yet. */
+       vcpu_load(vcpu->kvm, vcpu_slot(vcpu));
+}
+EXPORT_SYMBOL_GPL(kvm_resched);
+
+void load_msrs(struct vmx_msr_entry *e, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i)
+               wrmsrl(e[i].index, e[i].data);
+}
+EXPORT_SYMBOL_GPL(load_msrs);
+
+void save_msrs(struct vmx_msr_entry *e, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i)
+               rdmsrl(e[i].index, e[i].data);
+}
+EXPORT_SYMBOL_GPL(save_msrs);
+
+static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
+{
+       struct kvm_vcpu *vcpu;
+       int r;
+
+       if (kvm_run->vcpu < 0 || kvm_run->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+
+       vcpu = vcpu_load(kvm, kvm_run->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       if (kvm_run->emulated) {
+               kvm_arch_ops->skip_emulated_instruction(vcpu);
+               kvm_run->emulated = 0;
+       }
+
+       if (kvm_run->mmio_completed) {
+               memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
+               vcpu->mmio_read_completed = 1;
+       }
+
+       vcpu->mmio_needed = 0;
+
+       r = kvm_arch_ops->run(vcpu, kvm_run);
+
+       vcpu_put(vcpu);
+       return r;
+}
+
+static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
+{
+       struct kvm_vcpu *vcpu;
+
+       if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+
+       vcpu = vcpu_load(kvm, regs->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       kvm_arch_ops->cache_regs(vcpu);
+
+       regs->rax = vcpu->regs[VCPU_REGS_RAX];
+       regs->rbx = vcpu->regs[VCPU_REGS_RBX];
+       regs->rcx = vcpu->regs[VCPU_REGS_RCX];
+       regs->rdx = vcpu->regs[VCPU_REGS_RDX];
+       regs->rsi = vcpu->regs[VCPU_REGS_RSI];
+       regs->rdi = vcpu->regs[VCPU_REGS_RDI];
+       regs->rsp = vcpu->regs[VCPU_REGS_RSP];
+       regs->rbp = vcpu->regs[VCPU_REGS_RBP];
+#ifdef __x86_64__
+       regs->r8 = vcpu->regs[VCPU_REGS_R8];
+       regs->r9 = vcpu->regs[VCPU_REGS_R9];
+       regs->r10 = vcpu->regs[VCPU_REGS_R10];
+       regs->r11 = vcpu->regs[VCPU_REGS_R11];
+       regs->r12 = vcpu->regs[VCPU_REGS_R12];
+       regs->r13 = vcpu->regs[VCPU_REGS_R13];
+       regs->r14 = vcpu->regs[VCPU_REGS_R14];
+       regs->r15 = vcpu->regs[VCPU_REGS_R15];
+#endif
+
+       regs->rip = vcpu->rip;
+       regs->rflags = kvm_arch_ops->get_rflags(vcpu);
+
+       /*
+        * Don't leak debug flags in case they were set for guest debugging
+        */
+       if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep)
+               regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs)
+{
+       struct kvm_vcpu *vcpu;
+
+       if (regs->vcpu < 0 || regs->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+
+       vcpu = vcpu_load(kvm, regs->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       vcpu->regs[VCPU_REGS_RAX] = regs->rax;
+       vcpu->regs[VCPU_REGS_RBX] = regs->rbx;
+       vcpu->regs[VCPU_REGS_RCX] = regs->rcx;
+       vcpu->regs[VCPU_REGS_RDX] = regs->rdx;
+       vcpu->regs[VCPU_REGS_RSI] = regs->rsi;
+       vcpu->regs[VCPU_REGS_RDI] = regs->rdi;
+       vcpu->regs[VCPU_REGS_RSP] = regs->rsp;
+       vcpu->regs[VCPU_REGS_RBP] = regs->rbp;
+#ifdef __x86_64__
+       vcpu->regs[VCPU_REGS_R8] = regs->r8;
+       vcpu->regs[VCPU_REGS_R9] = regs->r9;
+       vcpu->regs[VCPU_REGS_R10] = regs->r10;
+       vcpu->regs[VCPU_REGS_R11] = regs->r11;
+       vcpu->regs[VCPU_REGS_R12] = regs->r12;
+       vcpu->regs[VCPU_REGS_R13] = regs->r13;
+       vcpu->regs[VCPU_REGS_R14] = regs->r14;
+       vcpu->regs[VCPU_REGS_R15] = regs->r15;
+#endif
+
+       vcpu->rip = regs->rip;
+       kvm_arch_ops->set_rflags(vcpu, regs->rflags);
+
+       kvm_arch_ops->decache_regs(vcpu);
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static void get_segment(struct kvm_vcpu *vcpu,
+                       struct kvm_segment *var, int seg)
+{
+       return kvm_arch_ops->get_segment(vcpu, var, seg);
+}
+
+static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+{
+       struct kvm_vcpu *vcpu;
+       struct descriptor_table dt;
+
+       if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+       vcpu = vcpu_load(kvm, sregs->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+       get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+       get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+       get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+       get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+       get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+       get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+       get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+       kvm_arch_ops->get_idt(vcpu, &dt);
+       sregs->idt.limit = dt.limit;
+       sregs->idt.base = dt.base;
+       kvm_arch_ops->get_gdt(vcpu, &dt);
+       sregs->gdt.limit = dt.limit;
+       sregs->gdt.base = dt.base;
+
+       sregs->cr0 = vcpu->cr0;
+       sregs->cr2 = vcpu->cr2;
+       sregs->cr3 = vcpu->cr3;
+       sregs->cr4 = vcpu->cr4;
+       sregs->cr8 = vcpu->cr8;
+       sregs->efer = vcpu->shadow_efer;
+       sregs->apic_base = vcpu->apic_base;
+
+       memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
+              sizeof sregs->interrupt_bitmap);
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static void set_segment(struct kvm_vcpu *vcpu,
+                       struct kvm_segment *var, int seg)
+{
+       return kvm_arch_ops->set_segment(vcpu, var, seg);
+}
+
+static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+{
+       struct kvm_vcpu *vcpu;
+       int mmu_reset_needed = 0;
+       int i;
+       struct descriptor_table dt;
+
+       if (sregs->vcpu < 0 || sregs->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+       vcpu = vcpu_load(kvm, sregs->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+       set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+       set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+       set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+       set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+       set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+       set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+       set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+       dt.limit = sregs->idt.limit;
+       dt.base = sregs->idt.base;
+       kvm_arch_ops->set_idt(vcpu, &dt);
+       dt.limit = sregs->gdt.limit;
+       dt.base = sregs->gdt.base;
+       kvm_arch_ops->set_gdt(vcpu, &dt);
+
+       vcpu->cr2 = sregs->cr2;
+       mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
+       vcpu->cr3 = sregs->cr3;
+
+       vcpu->cr8 = sregs->cr8;
+
+       mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
+#ifdef __x86_64__
+       kvm_arch_ops->set_efer(vcpu, sregs->efer);
+#endif
+       vcpu->apic_base = sregs->apic_base;
+
+       mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
+       kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
+
+       mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
+       kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
+
+       if (mmu_reset_needed)
+               kvm_mmu_reset_context(vcpu);
+
+       memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
+              sizeof vcpu->irq_pending);
+       vcpu->irq_summary = 0;
+       for (i = 0; i < NR_IRQ_WORDS; ++i)
+               if (vcpu->irq_pending[i])
+                       __set_bit(i, &vcpu->irq_summary);
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+/*
+ * List of msr numbers which we expose to userspace through KVM_GET_MSRS
+ * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
+ */
+static u32 msrs_to_save[] = {
+       MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+       MSR_K6_STAR,
+#ifdef __x86_64__
+       MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
+#endif
+       MSR_IA32_TIME_STAMP_COUNTER,
+};
+
+
+/*
+ * Adapt set_msr() to msr_io()'s calling convention
+ */
+static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
+{
+       return set_msr(vcpu, index, *data);
+}
+
+/*
+ * Read or write a bunch of msrs. All parameters are kernel addresses.
+ *
+ * @return number of msrs set successfully.
+ */
+static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs,
+                   struct kvm_msr_entry *entries,
+                   int (*do_msr)(struct kvm_vcpu *vcpu,
+                                 unsigned index, u64 *data))
+{
+       struct kvm_vcpu *vcpu;
+       int i;
+
+       if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+
+       vcpu = vcpu_load(kvm, msrs->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       for (i = 0; i < msrs->nmsrs; ++i)
+               if (do_msr(vcpu, entries[i].index, &entries[i].data))
+                       break;
+
+       vcpu_put(vcpu);
+
+       return i;
+}
+
+/*
+ * Read or write a bunch of msrs. Parameters are user addresses.
+ *
+ * @return number of msrs set successfully.
+ */
+static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs,
+                 int (*do_msr)(struct kvm_vcpu *vcpu,
+                               unsigned index, u64 *data),
+                 int writeback)
+{
+       struct kvm_msrs msrs;
+       struct kvm_msr_entry *entries;
+       int r, n;
+       unsigned size;
+
+       r = -EFAULT;
+       if (copy_from_user(&msrs, user_msrs, sizeof msrs))
+               goto out;
+
+       r = -E2BIG;
+       if (msrs.nmsrs >= MAX_IO_MSRS)
+               goto out;
+
+       r = -ENOMEM;
+       size = sizeof(struct kvm_msr_entry) * msrs.nmsrs;
+       entries = vmalloc(size);
+       if (!entries)
+               goto out;
+
+       r = -EFAULT;
+       if (copy_from_user(entries, user_msrs->entries, size))
+               goto out_free;
+
+       r = n = __msr_io(kvm, &msrs, entries, do_msr);
+       if (r < 0)
+               goto out_free;
+
+       r = -EFAULT;
+       if (writeback && copy_to_user(user_msrs->entries, entries, size))
+               goto out_free;
+
+       r = n;
+
+out_free:
+       vfree(entries);
+out:
+       return r;
+}
+
+/*
+ * Translate a guest virtual address to a guest physical address.
+ */
+static int kvm_dev_ioctl_translate(struct kvm *kvm, struct kvm_translation *tr)
+{
+       unsigned long vaddr = tr->linear_address;
+       struct kvm_vcpu *vcpu;
+       gpa_t gpa;
+
+       vcpu = vcpu_load(kvm, tr->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+       spin_lock(&kvm->lock);
+       gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
+       tr->physical_address = gpa;
+       tr->valid = gpa != UNMAPPED_GVA;
+       tr->writeable = 1;
+       tr->usermode = 0;
+       spin_unlock(&kvm->lock);
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq)
+{
+       struct kvm_vcpu *vcpu;
+
+       if (irq->vcpu < 0 || irq->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+       if (irq->irq < 0 || irq->irq >= 256)
+               return -EINVAL;
+       vcpu = vcpu_load(kvm, irq->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       set_bit(irq->irq, vcpu->irq_pending);
+       set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary);
+
+       vcpu_put(vcpu);
+
+       return 0;
+}
+
+static int kvm_dev_ioctl_debug_guest(struct kvm *kvm,
+                                    struct kvm_debug_guest *dbg)
+{
+       struct kvm_vcpu *vcpu;
+       int r;
+
+       if (dbg->vcpu < 0 || dbg->vcpu >= KVM_MAX_VCPUS)
+               return -EINVAL;
+       vcpu = vcpu_load(kvm, dbg->vcpu);
+       if (!vcpu)
+               return -ENOENT;
+
+       r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
+
+       vcpu_put(vcpu);
+
+       return r;
+}
+
+static long kvm_dev_ioctl(struct file *filp,
+                         unsigned int ioctl, unsigned long arg)
+{
+       struct kvm *kvm = filp->private_data;
+       int r = -EINVAL;
+
+       switch (ioctl) {
+       case KVM_CREATE_VCPU: {
+               r = kvm_dev_ioctl_create_vcpu(kvm, arg);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_RUN: {
+               struct kvm_run kvm_run;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run))
+                       goto out;
+               r = kvm_dev_ioctl_run(kvm, &kvm_run);
+               if (r < 0)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_GET_REGS: {
+               struct kvm_regs kvm_regs;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+                       goto out;
+               r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
+               if (r)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_REGS: {
+               struct kvm_regs kvm_regs;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+                       goto out;
+               r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_GET_SREGS: {
+               struct kvm_sregs kvm_sregs;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+                       goto out;
+               r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
+               if (r)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_SREGS: {
+               struct kvm_sregs kvm_sregs;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+                       goto out;
+               r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_TRANSLATE: {
+               struct kvm_translation tr;
+
+               r = -EFAULT;
+               if (copy_from_user(&tr, (void *)arg, sizeof tr))
+                       goto out;
+               r = kvm_dev_ioctl_translate(kvm, &tr);
+               if (r)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user((void *)arg, &tr, sizeof tr))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_INTERRUPT: {
+               struct kvm_interrupt irq;
+
+               r = -EFAULT;
+               if (copy_from_user(&irq, (void *)arg, sizeof irq))
+                       goto out;
+               r = kvm_dev_ioctl_interrupt(kvm, &irq);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_DEBUG_GUEST: {
+               struct kvm_debug_guest dbg;
+
+               r = -EFAULT;
+               if (copy_from_user(&dbg, (void *)arg, sizeof dbg))
+                       goto out;
+               r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_SET_MEMORY_REGION: {
+               struct kvm_memory_region kvm_mem;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem))
+                       goto out;
+               r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_GET_DIRTY_LOG: {
+               struct kvm_dirty_log log;
+
+               r = -EFAULT;
+               if (copy_from_user(&log, (void *)arg, sizeof log))
+                       goto out;
+               r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_GET_MSRS:
+               r = msr_io(kvm, (void __user *)arg, get_msr, 1);
+               break;
+       case KVM_SET_MSRS:
+               r = msr_io(kvm, (void __user *)arg, do_set_msr, 0);
+               break;
+       case KVM_GET_MSR_INDEX_LIST: {
+               struct kvm_msr_list __user *user_msr_list = (void __user *)arg;
+               struct kvm_msr_list msr_list;
+               unsigned n;
+
+               r = -EFAULT;
+               if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
+                       goto out;
+               n = msr_list.nmsrs;
+               msr_list.nmsrs = ARRAY_SIZE(msrs_to_save);
+               if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
+                       goto out;
+               r = -E2BIG;
+               if (n < ARRAY_SIZE(msrs_to_save))
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user(user_msr_list->indices, &msrs_to_save,
+                                sizeof msrs_to_save))
+                       goto out;
+               r = 0;
+       }
+       default:
+               ;
+       }
+out:
+       return r;
+}
+
+static struct page *kvm_dev_nopage(struct vm_area_struct *vma,
+                                  unsigned long address,
+                                  int *type)
+{
+       struct kvm *kvm = vma->vm_file->private_data;
+       unsigned long pgoff;
+       struct kvm_memory_slot *slot;
+       struct page *page;
+
+       *type = VM_FAULT_MINOR;
+       pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+       slot = gfn_to_memslot(kvm, pgoff);
+       if (!slot)
+               return NOPAGE_SIGBUS;
+       page = gfn_to_page(slot, pgoff);
+       if (!page)
+               return NOPAGE_SIGBUS;
+       get_page(page);
+       return page;
+}
+
+static struct vm_operations_struct kvm_dev_vm_ops = {
+       .nopage = kvm_dev_nopage,
+};
+
+static int kvm_dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       vma->vm_ops = &kvm_dev_vm_ops;
+       return 0;
+}
+
+static struct file_operations kvm_chardev_ops = {
+       .open           = kvm_dev_open,
+       .release        = kvm_dev_release,
+       .unlocked_ioctl = kvm_dev_ioctl,
+       .compat_ioctl   = kvm_dev_ioctl,
+       .mmap           = kvm_dev_mmap,
+};
+
+static struct miscdevice kvm_dev = {
+       MISC_DYNAMIC_MINOR,
+       "kvm",
+       &kvm_chardev_ops,
+};
+
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+                       void *v)
+{
+       if (val == SYS_RESTART) {
+               /*
+                * Some (well, at least mine) BIOSes hang on reboot if
+                * in vmx root mode.
+                */
+               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+               on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+       .notifier_call = kvm_reboot,
+       .priority = 0,
+};
+
+static __init void kvm_init_debug(void)
+{
+       struct kvm_stats_debugfs_item *p;
+
+       debugfs_dir = debugfs_create_dir("kvm", 0);
+       for (p = debugfs_entries; p->name; ++p)
+               p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
+                                              p->data);
+}
+
+static void kvm_exit_debug(void)
+{
+       struct kvm_stats_debugfs_item *p;
+
+       for (p = debugfs_entries; p->name; ++p)
+               debugfs_remove(p->dentry);
+       debugfs_remove(debugfs_dir);
+}
+
+hpa_t bad_page_address;
+
+int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+{
+       int r;
+
+       kvm_arch_ops = ops;
+
+       if (!kvm_arch_ops->cpu_has_kvm_support()) {
+               printk(KERN_ERR "kvm: no hardware support\n");
+               return -EOPNOTSUPP;
+       }
+       if (kvm_arch_ops->disabled_by_bios()) {
+               printk(KERN_ERR "kvm: disabled by bios\n");
+               return -EOPNOTSUPP;
+       }
+
+       r = kvm_arch_ops->hardware_setup();
+       if (r < 0)
+           return r;
+
+       on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+       register_reboot_notifier(&kvm_reboot_notifier);
+
+       kvm_chardev_ops.owner = module;
+
+       r = misc_register(&kvm_dev);
+       if (r) {
+               printk (KERN_ERR "kvm: misc device register failed\n");
+               goto out_free;
+       }
+
+       return r;
+
+out_free:
+       unregister_reboot_notifier(&kvm_reboot_notifier);
+       on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+       kvm_arch_ops->hardware_unsetup();
+       return r;
+}
+
+void kvm_exit_arch(void)
+{
+       misc_deregister(&kvm_dev);
+
+       unregister_reboot_notifier(&kvm_reboot_notifier);
+       on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+       kvm_arch_ops->hardware_unsetup();
+}
+
+static __init int kvm_init(void)
+{
+       static struct page *bad_page;
+       int r = 0;
+
+       kvm_init_debug();
+
+       if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT;
+       memset(__va(bad_page_address), 0, PAGE_SIZE);
+
+       return r;
+
+out:
+       kvm_exit_debug();
+       return r;
+}
+
+static __exit void kvm_exit(void)
+{
+       kvm_exit_debug();
+       __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
+}
+
+module_init(kvm_init)
+module_exit(kvm_exit)
+
+EXPORT_SYMBOL_GPL(kvm_init_arch);
+EXPORT_SYMBOL_GPL(kvm_exit_arch);
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
new file mode 100644 (file)
index 0000000..7d7f2aa
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __KVM_SVM_H
+#define __KVM_SVM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/msr.h>
+
+#include "svm.h"
+#include "kvm.h"
+
+static const u32 host_save_msrs[] = {
+#ifdef __x86_64__
+       MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
+       MSR_FS_BASE, MSR_GS_BASE,
+#endif
+       MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+       MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP,
+       MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
+};
+
+#define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs))
+#define NUM_DB_REGS 4
+
+struct vcpu_svm {
+       struct vmcb *vmcb;
+       unsigned long vmcb_pa;
+       struct svm_cpu_data *svm_data;
+       uint64_t asid_generation;
+
+       unsigned long cr0;
+       unsigned long cr4;
+       unsigned long db_regs[NUM_DB_REGS];
+
+       u64 next_rip;
+
+       u64 host_msrs[NR_HOST_SAVE_MSRS];
+       unsigned long host_cr2;
+       unsigned long host_db_regs[NUM_DB_REGS];
+       unsigned long host_dr6;
+       unsigned long host_dr7;
+};
+
+#endif
+
diff --git a/drivers/kvm/kvm_vmx.h b/drivers/kvm/kvm_vmx.h
new file mode 100644 (file)
index 0000000..87e12d2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __KVM_VMX_H
+#define __KVM_VMX_H
+
+#ifdef __x86_64__
+/*
+ * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
+ * mechanism (cpu bug AA24)
+ */
+#define NR_BAD_MSRS 2
+#else
+#define NR_BAD_MSRS 0
+#endif
+
+#endif
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
new file mode 100644 (file)
index 0000000..4e29d9b
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * MMU support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/page.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+#include "vmx.h"
+#include "kvm.h"
+
+#define pgprintk(x...) do { } while (0)
+
+#define ASSERT(x)                                                      \
+       if (!(x)) {                                                     \
+               printk(KERN_WARNING "assertion failed %s:%d: %s\n",     \
+                      __FILE__, __LINE__, #x);                         \
+       }
+
+#define PT64_ENT_PER_PAGE 512
+#define PT32_ENT_PER_PAGE 1024
+
+#define PT_WRITABLE_SHIFT 1
+
+#define PT_PRESENT_MASK (1ULL << 0)
+#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
+#define PT_USER_MASK (1ULL << 2)
+#define PT_PWT_MASK (1ULL << 3)
+#define PT_PCD_MASK (1ULL << 4)
+#define PT_ACCESSED_MASK (1ULL << 5)
+#define PT_DIRTY_MASK (1ULL << 6)
+#define PT_PAGE_SIZE_MASK (1ULL << 7)
+#define PT_PAT_MASK (1ULL << 7)
+#define PT_GLOBAL_MASK (1ULL << 8)
+#define PT64_NX_MASK (1ULL << 63)
+
+#define PT_PAT_SHIFT 7
+#define PT_DIR_PAT_SHIFT 12
+#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT)
+
+#define PT32_DIR_PSE36_SIZE 4
+#define PT32_DIR_PSE36_SHIFT 13
+#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT)
+
+
+#define PT32_PTE_COPY_MASK \
+       (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK | \
+       PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_PAT_MASK | \
+       PT_GLOBAL_MASK )
+
+#define PT32_NON_PTE_COPY_MASK \
+       (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK | \
+       PT_ACCESSED_MASK | PT_DIRTY_MASK)
+
+
+#define PT64_PTE_COPY_MASK \
+       (PT64_NX_MASK | PT32_PTE_COPY_MASK)
+
+#define PT64_NON_PTE_COPY_MASK \
+       (PT64_NX_MASK | PT32_NON_PTE_COPY_MASK)
+
+
+
+#define PT_FIRST_AVAIL_BITS_SHIFT 9
+#define PT64_SECOND_AVAIL_BITS_SHIFT 52
+
+#define PT_SHADOW_PS_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+
+#define PT_SHADOW_WRITABLE_SHIFT (PT_FIRST_AVAIL_BITS_SHIFT + 1)
+#define PT_SHADOW_WRITABLE_MASK (1ULL << PT_SHADOW_WRITABLE_SHIFT)
+
+#define PT_SHADOW_USER_SHIFT (PT_SHADOW_WRITABLE_SHIFT + 1)
+#define PT_SHADOW_USER_MASK (1ULL << (PT_SHADOW_USER_SHIFT))
+
+#define PT_SHADOW_BITS_OFFSET (PT_SHADOW_WRITABLE_SHIFT - PT_WRITABLE_SHIFT)
+
+#define VALID_PAGE(x) ((x) != INVALID_PAGE)
+
+#define PT64_LEVEL_BITS 9
+
+#define PT64_LEVEL_SHIFT(level) \
+               ( PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS )
+
+#define PT64_LEVEL_MASK(level) \
+               (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level))
+
+#define PT64_INDEX(address, level)\
+       (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1))
+
+
+#define PT32_LEVEL_BITS 10
+
+#define PT32_LEVEL_SHIFT(level) \
+               ( PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS )
+
+#define PT32_LEVEL_MASK(level) \
+               (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level))
+
+#define PT32_INDEX(address, level)\
+       (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1))
+
+
+#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & PAGE_MASK)
+#define PT64_DIR_BASE_ADDR_MASK \
+       (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1))
+
+#define PT32_BASE_ADDR_MASK PAGE_MASK
+#define PT32_DIR_BASE_ADDR_MASK \
+       (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1))
+
+
+#define PFERR_PRESENT_MASK (1U << 0)
+#define PFERR_WRITE_MASK (1U << 1)
+#define PFERR_USER_MASK (1U << 2)
+
+#define PT64_ROOT_LEVEL 4
+#define PT32_ROOT_LEVEL 2
+#define PT32E_ROOT_LEVEL 3
+
+#define PT_DIRECTORY_LEVEL 2
+#define PT_PAGE_TABLE_LEVEL 1
+
+static int is_write_protection(struct kvm_vcpu *vcpu)
+{
+       return vcpu->cr0 & CR0_WP_MASK;
+}
+
+static int is_cpuid_PSE36(void)
+{
+       return 1;
+}
+
+static int is_present_pte(unsigned long pte)
+{
+       return pte & PT_PRESENT_MASK;
+}
+
+static int is_writeble_pte(unsigned long pte)
+{
+       return pte & PT_WRITABLE_MASK;
+}
+
+static int is_io_pte(unsigned long pte)
+{
+       return pte & PT_SHADOW_IO_MARK;
+}
+
+static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
+{
+       struct kvm_mmu_page *page_head = page_header(page_hpa);
+
+       list_del(&page_head->link);
+       page_head->page_hpa = page_hpa;
+       list_add(&page_head->link, &vcpu->free_pages);
+}
+
+static int is_empty_shadow_page(hpa_t page_hpa)
+{
+       u32 *pos;
+       u32 *end;
+       for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u32);
+                     pos != end; pos++)
+               if (*pos != 0)
+                       return 0;
+       return 1;
+}
+
+static hpa_t kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, u64 *parent_pte)
+{
+       struct kvm_mmu_page *page;
+
+       if (list_empty(&vcpu->free_pages))
+               return INVALID_PAGE;
+
+       page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
+       list_del(&page->link);
+       list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+       ASSERT(is_empty_shadow_page(page->page_hpa));
+       page->slot_bitmap = 0;
+       page->global = 1;
+       page->parent_pte = parent_pte;
+       return page->page_hpa;
+}
+
+static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa)
+{
+       int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT));
+       struct kvm_mmu_page *page_head = page_header(__pa(pte));
+
+       __set_bit(slot, &page_head->slot_bitmap);
+}
+
+hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+       hpa_t hpa = gpa_to_hpa(vcpu, gpa);
+
+       return is_error_hpa(hpa) ? bad_page_address | (gpa & ~PAGE_MASK): hpa;
+}
+
+hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+       struct kvm_memory_slot *slot;
+       struct page *page;
+
+       ASSERT((gpa & HPA_ERR_MASK) == 0);
+       slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
+       if (!slot)
+               return gpa | HPA_ERR_MASK;
+       page = gfn_to_page(slot, gpa >> PAGE_SHIFT);
+       return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT)
+               | (gpa & (PAGE_SIZE-1));
+}
+
+hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva)
+{
+       gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
+
+       if (gpa == UNMAPPED_GVA)
+               return UNMAPPED_GVA;
+       return gpa_to_hpa(vcpu, gpa);
+}
+
+
+static void release_pt_page_64(struct kvm_vcpu *vcpu, hpa_t page_hpa,
+                              int level)
+{
+       ASSERT(vcpu);
+       ASSERT(VALID_PAGE(page_hpa));
+       ASSERT(level <= PT64_ROOT_LEVEL && level > 0);
+
+       if (level == 1)
+               memset(__va(page_hpa), 0, PAGE_SIZE);
+       else {
+               u64 *pos;
+               u64 *end;
+
+               for (pos = __va(page_hpa), end = pos + PT64_ENT_PER_PAGE;
+                    pos != end; pos++) {
+                       u64 current_ent = *pos;
+
+                       *pos = 0;
+                       if (is_present_pte(current_ent))
+                               release_pt_page_64(vcpu,
+                                                 current_ent &
+                                                 PT64_BASE_ADDR_MASK,
+                                                 level - 1);
+               }
+       }
+       kvm_mmu_free_page(vcpu, page_hpa);
+}
+
+static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
+{
+}
+
+static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
+{
+       int level = PT32E_ROOT_LEVEL;
+       hpa_t table_addr = vcpu->mmu.root_hpa;
+
+       for (; ; level--) {
+               u32 index = PT64_INDEX(v, level);
+               u64 *table;
+
+               ASSERT(VALID_PAGE(table_addr));
+               table = __va(table_addr);
+
+               if (level == 1) {
+                       mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT);
+                       page_header_update_slot(vcpu->kvm, table, v);
+                       table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK |
+                                                               PT_USER_MASK;
+                       return 0;
+               }
+
+               if (table[index] == 0) {
+                       hpa_t new_table = kvm_mmu_alloc_page(vcpu,
+                                                            &table[index]);
+
+                       if (!VALID_PAGE(new_table)) {
+                               pgprintk("nonpaging_map: ENOMEM\n");
+                               return -ENOMEM;
+                       }
+
+                       if (level == PT32E_ROOT_LEVEL)
+                               table[index] = new_table | PT_PRESENT_MASK;
+                       else
+                               table[index] = new_table | PT_PRESENT_MASK |
+                                               PT_WRITABLE_MASK | PT_USER_MASK;
+               }
+               table_addr = table[index] & PT64_BASE_ADDR_MASK;
+       }
+}
+
+static void nonpaging_flush(struct kvm_vcpu *vcpu)
+{
+       hpa_t root = vcpu->mmu.root_hpa;
+
+       ++kvm_stat.tlb_flush;
+       pgprintk("nonpaging_flush\n");
+       ASSERT(VALID_PAGE(root));
+       release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level);
+       root = kvm_mmu_alloc_page(vcpu, NULL);
+       ASSERT(VALID_PAGE(root));
+       vcpu->mmu.root_hpa = root;
+       if (is_paging(vcpu))
+               root |= (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK));
+       kvm_arch_ops->set_cr3(vcpu, root);
+       kvm_arch_ops->tlb_flush(vcpu);
+}
+
+static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
+{
+       return vaddr;
+}
+
+static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
+                              u32 error_code)
+{
+       int ret;
+       gpa_t addr = gva;
+
+       ASSERT(vcpu);
+       ASSERT(VALID_PAGE(vcpu->mmu.root_hpa));
+
+       for (;;) {
+            hpa_t paddr;
+
+            paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK);
+
+            if (is_error_hpa(paddr))
+                    return 1;
+
+            ret = nonpaging_map(vcpu, addr & PAGE_MASK, paddr);
+            if (ret) {
+                    nonpaging_flush(vcpu);
+                    continue;
+            }
+            break;
+       }
+       return ret;
+}
+
+static void nonpaging_inval_page(struct kvm_vcpu *vcpu, gva_t addr)
+{
+}
+
+static void nonpaging_free(struct kvm_vcpu *vcpu)
+{
+       hpa_t root;
+
+       ASSERT(vcpu);
+       root = vcpu->mmu.root_hpa;
+       if (VALID_PAGE(root))
+               release_pt_page_64(vcpu, root, vcpu->mmu.shadow_root_level);
+       vcpu->mmu.root_hpa = INVALID_PAGE;
+}
+
+static int nonpaging_init_context(struct kvm_vcpu *vcpu)
+{
+       struct kvm_mmu *context = &vcpu->mmu;
+
+       context->new_cr3 = nonpaging_new_cr3;
+       context->page_fault = nonpaging_page_fault;
+       context->inval_page = nonpaging_inval_page;
+       context->gva_to_gpa = nonpaging_gva_to_gpa;
+       context->free = nonpaging_free;
+       context->root_level = PT32E_ROOT_LEVEL;
+       context->shadow_root_level = PT32E_ROOT_LEVEL;
+       context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL);
+       ASSERT(VALID_PAGE(context->root_hpa));
+       kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
+       return 0;
+}
+
+
+static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
+{
+       struct kvm_mmu_page *page, *npage;
+
+       list_for_each_entry_safe(page, npage, &vcpu->kvm->active_mmu_pages,
+                                link) {
+               if (page->global)
+                       continue;
+
+               if (!page->parent_pte)
+                       continue;
+
+               *page->parent_pte = 0;
+               release_pt_page_64(vcpu, page->page_hpa, 1);
+       }
+       ++kvm_stat.tlb_flush;
+       kvm_arch_ops->tlb_flush(vcpu);
+}
+
+static void paging_new_cr3(struct kvm_vcpu *vcpu)
+{
+       kvm_mmu_flush_tlb(vcpu);
+}
+
+static void mark_pagetable_nonglobal(void *shadow_pte)
+{
+       page_header(__pa(shadow_pte))->global = 0;
+}
+
+static inline void set_pte_common(struct kvm_vcpu *vcpu,
+                            u64 *shadow_pte,
+                            gpa_t gaddr,
+                            int dirty,
+                            u64 access_bits)
+{
+       hpa_t paddr;
+
+       *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET;
+       if (!dirty)
+               access_bits &= ~PT_WRITABLE_MASK;
+
+       if (access_bits & PT_WRITABLE_MASK)
+               mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
+
+       *shadow_pte |= access_bits;
+
+       paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
+
+       if (!(*shadow_pte & PT_GLOBAL_MASK))
+               mark_pagetable_nonglobal(shadow_pte);
+
+       if (is_error_hpa(paddr)) {
+               *shadow_pte |= gaddr;
+               *shadow_pte |= PT_SHADOW_IO_MARK;
+               *shadow_pte &= ~PT_PRESENT_MASK;
+       } else {
+               *shadow_pte |= paddr;
+               page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
+       }
+}
+
+static void inject_page_fault(struct kvm_vcpu *vcpu,
+                             u64 addr,
+                             u32 err_code)
+{
+       kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
+}
+
+static inline int fix_read_pf(u64 *shadow_ent)
+{
+       if ((*shadow_ent & PT_SHADOW_USER_MASK) &&
+           !(*shadow_ent & PT_USER_MASK)) {
+               /*
+                * If supervisor write protect is disabled, we shadow kernel
+                * pages as user pages so we can trap the write access.
+                */
+               *shadow_ent |= PT_USER_MASK;
+               *shadow_ent &= ~PT_WRITABLE_MASK;
+
+               return 1;
+
+       }
+       return 0;
+}
+
+static int may_access(u64 pte, int write, int user)
+{
+
+       if (user && !(pte & PT_USER_MASK))
+               return 0;
+       if (write && !(pte & PT_WRITABLE_MASK))
+               return 0;
+       return 1;
+}
+
+/*
+ * Remove a shadow pte.
+ */
+static void paging_inval_page(struct kvm_vcpu *vcpu, gva_t addr)
+{
+       hpa_t page_addr = vcpu->mmu.root_hpa;
+       int level = vcpu->mmu.shadow_root_level;
+
+       ++kvm_stat.invlpg;
+
+       for (; ; level--) {
+               u32 index = PT64_INDEX(addr, level);
+               u64 *table = __va(page_addr);
+
+               if (level == PT_PAGE_TABLE_LEVEL ) {
+                       table[index] = 0;
+                       return;
+               }
+
+               if (!is_present_pte(table[index]))
+                       return;
+
+               page_addr = table[index] & PT64_BASE_ADDR_MASK;
+
+               if (level == PT_DIRECTORY_LEVEL &&
+                         (table[index] & PT_SHADOW_PS_MARK)) {
+                       table[index] = 0;
+                       release_pt_page_64(vcpu, page_addr, PT_PAGE_TABLE_LEVEL);
+
+                       kvm_arch_ops->tlb_flush(vcpu);
+                       return;
+               }
+       }
+}
+
+static void paging_free(struct kvm_vcpu *vcpu)
+{
+       nonpaging_free(vcpu);
+}
+
+#define PTTYPE 64
+#include "paging_tmpl.h"
+#undef PTTYPE
+
+#define PTTYPE 32
+#include "paging_tmpl.h"
+#undef PTTYPE
+
+static int paging64_init_context(struct kvm_vcpu *vcpu)
+{
+       struct kvm_mmu *context = &vcpu->mmu;
+
+       ASSERT(is_pae(vcpu));
+       context->new_cr3 = paging_new_cr3;
+       context->page_fault = paging64_page_fault;
+       context->inval_page = paging_inval_page;
+       context->gva_to_gpa = paging64_gva_to_gpa;
+       context->free = paging_free;
+       context->root_level = PT64_ROOT_LEVEL;
+       context->shadow_root_level = PT64_ROOT_LEVEL;
+       context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL);
+       ASSERT(VALID_PAGE(context->root_hpa));
+       kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
+                   (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+       return 0;
+}
+
+static int paging32_init_context(struct kvm_vcpu *vcpu)
+{
+       struct kvm_mmu *context = &vcpu->mmu;
+
+       context->new_cr3 = paging_new_cr3;
+       context->page_fault = paging32_page_fault;
+       context->inval_page = paging_inval_page;
+       context->gva_to_gpa = paging32_gva_to_gpa;
+       context->free = paging_free;
+       context->root_level = PT32_ROOT_LEVEL;
+       context->shadow_root_level = PT32E_ROOT_LEVEL;
+       context->root_hpa = kvm_mmu_alloc_page(vcpu, NULL);
+       ASSERT(VALID_PAGE(context->root_hpa));
+       kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
+                   (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+       return 0;
+}
+
+static int paging32E_init_context(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       if ((ret = paging64_init_context(vcpu)))
+               return ret;
+
+       vcpu->mmu.root_level = PT32E_ROOT_LEVEL;
+       vcpu->mmu.shadow_root_level = PT32E_ROOT_LEVEL;
+       return 0;
+}
+
+static int init_kvm_mmu(struct kvm_vcpu *vcpu)
+{
+       ASSERT(vcpu);
+       ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
+
+       if (!is_paging(vcpu))
+               return nonpaging_init_context(vcpu);
+       else if (kvm_arch_ops->is_long_mode(vcpu))
+               return paging64_init_context(vcpu);
+       else if (is_pae(vcpu))
+               return paging32E_init_context(vcpu);
+       else
+               return paging32_init_context(vcpu);
+}
+
+static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
+{
+       ASSERT(vcpu);
+       if (VALID_PAGE(vcpu->mmu.root_hpa)) {
+               vcpu->mmu.free(vcpu);
+               vcpu->mmu.root_hpa = INVALID_PAGE;
+       }
+}
+
+int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
+{
+       destroy_kvm_mmu(vcpu);
+       return init_kvm_mmu(vcpu);
+}
+
+static void free_mmu_pages(struct kvm_vcpu *vcpu)
+{
+       while (!list_empty(&vcpu->free_pages)) {
+               struct kvm_mmu_page *page;
+
+               page = list_entry(vcpu->free_pages.next,
+                                 struct kvm_mmu_page, link);
+               list_del(&page->link);
+               __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT));
+               page->page_hpa = INVALID_PAGE;
+       }
+}
+
+static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
+{
+       int i;
+
+       ASSERT(vcpu);
+
+       for (i = 0; i < KVM_NUM_MMU_PAGES; i++) {
+               struct page *page;
+               struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i];
+
+               INIT_LIST_HEAD(&page_header->link);
+               if ((page = alloc_page(GFP_KVM_MMU)) == NULL)
+                       goto error_1;
+               page->private = (unsigned long)page_header;
+               page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT;
+               memset(__va(page_header->page_hpa), 0, PAGE_SIZE);
+               list_add(&page_header->link, &vcpu->free_pages);
+       }
+       return 0;
+
+error_1:
+       free_mmu_pages(vcpu);
+       return -ENOMEM;
+}
+
+int kvm_mmu_init(struct kvm_vcpu *vcpu)
+{
+       int r;
+
+       ASSERT(vcpu);
+       ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
+       ASSERT(list_empty(&vcpu->free_pages));
+
+       if ((r = alloc_mmu_pages(vcpu)))
+               return r;
+
+       if ((r = init_kvm_mmu(vcpu))) {
+               free_mmu_pages(vcpu);
+               return r;
+       }
+       return 0;
+}
+
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
+{
+       ASSERT(vcpu);
+
+       destroy_kvm_mmu(vcpu);
+       free_mmu_pages(vcpu);
+}
+
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
+{
+       struct kvm_mmu_page *page;
+
+       list_for_each_entry(page, &kvm->active_mmu_pages, link) {
+               int i;
+               u64 *pt;
+
+               if (!test_bit(slot, &page->slot_bitmap))
+                       continue;
+
+               pt = __va(page->page_hpa);
+               for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
+                       /* avoid RMW */
+                       if (pt[i] & PT_WRITABLE_MASK)
+                               pt[i] &= ~PT_WRITABLE_MASK;
+
+       }
+}
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
new file mode 100644 (file)
index 0000000..765c2e1
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * MMU support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+/*
+ * We need the mmu code to access both 32-bit and 64-bit guest ptes,
+ * so the code in this file is compiled twice, once per pte size.
+ */
+
+#if PTTYPE == 64
+       #define pt_element_t u64
+       #define guest_walker guest_walker64
+       #define FNAME(name) paging##64_##name
+       #define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK
+       #define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK
+       #define PT_INDEX(addr, level) PT64_INDEX(addr, level)
+       #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
+       #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
+       #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK
+       #define PT_NON_PTE_COPY_MASK PT64_NON_PTE_COPY_MASK
+#elif PTTYPE == 32
+       #define pt_element_t u32
+       #define guest_walker guest_walker32
+       #define FNAME(name) paging##32_##name
+       #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK
+       #define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK
+       #define PT_INDEX(addr, level) PT32_INDEX(addr, level)
+       #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
+       #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
+       #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK
+       #define PT_NON_PTE_COPY_MASK PT32_NON_PTE_COPY_MASK
+#else
+       #error Invalid PTTYPE value
+#endif
+
+/*
+ * The guest_walker structure emulates the behavior of the hardware page
+ * table walker.
+ */
+struct guest_walker {
+       int level;
+       pt_element_t *table;
+       pt_element_t inherited_ar;
+};
+
+static void FNAME(init_walker)(struct guest_walker *walker,
+                              struct kvm_vcpu *vcpu)
+{
+       hpa_t hpa;
+       struct kvm_memory_slot *slot;
+
+       walker->level = vcpu->mmu.root_level;
+       slot = gfn_to_memslot(vcpu->kvm,
+                             (vcpu->cr3 & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
+       hpa = safe_gpa_to_hpa(vcpu, vcpu->cr3 & PT64_BASE_ADDR_MASK);
+       walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
+
+       ASSERT((!kvm_arch_ops->is_long_mode(vcpu) && is_pae(vcpu)) ||
+              (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
+
+       walker->table = (pt_element_t *)( (unsigned long)walker->table |
+               (unsigned long)(vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) );
+       walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
+}
+
+static void FNAME(release_walker)(struct guest_walker *walker)
+{
+       kunmap_atomic(walker->table, KM_USER0);
+}
+
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte,
+                          u64 *shadow_pte, u64 access_bits)
+{
+       ASSERT(*shadow_pte == 0);
+       access_bits &= guest_pte;
+       *shadow_pte = (guest_pte & PT_PTE_COPY_MASK);
+       set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK,
+                      guest_pte & PT_DIRTY_MASK, access_bits);
+}
+
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde,
+                          u64 *shadow_pte, u64 access_bits,
+                          int index)
+{
+       gpa_t gaddr;
+
+       ASSERT(*shadow_pte == 0);
+       access_bits &= guest_pde;
+       gaddr = (guest_pde & PT_DIR_BASE_ADDR_MASK) + PAGE_SIZE * index;
+       if (PTTYPE == 32 && is_cpuid_PSE36())
+               gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) <<
+                       (32 - PT32_DIR_PSE36_SHIFT);
+       *shadow_pte = (guest_pde & (PT_NON_PTE_COPY_MASK | PT_GLOBAL_MASK)) |
+                         ((guest_pde & PT_DIR_PAT_MASK) >>
+                                   (PT_DIR_PAT_SHIFT - PT_PAT_SHIFT));
+       set_pte_common(vcpu, shadow_pte, gaddr,
+                      guest_pde & PT_DIRTY_MASK, access_bits);
+}
+
+/*
+ * Fetch a guest pte from a specific level in the paging hierarchy.
+ */
+static pt_element_t *FNAME(fetch_guest)(struct kvm_vcpu *vcpu,
+                                       struct guest_walker *walker,
+                                       int level,
+                                       gva_t addr)
+{
+
+       ASSERT(level > 0  && level <= walker->level);
+
+       for (;;) {
+               int index = PT_INDEX(addr, walker->level);
+               hpa_t paddr;
+
+               ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
+                      ((unsigned long)&walker->table[index] & PAGE_MASK));
+               if (level == walker->level ||
+                   !is_present_pte(walker->table[index]) ||
+                   (walker->level == PT_DIRECTORY_LEVEL &&
+                    (walker->table[index] & PT_PAGE_SIZE_MASK) &&
+                    (PTTYPE == 64 || is_pse(vcpu))))
+                       return &walker->table[index];
+               if (walker->level != 3 || kvm_arch_ops->is_long_mode(vcpu))
+                       walker->inherited_ar &= walker->table[index];
+               paddr = safe_gpa_to_hpa(vcpu, walker->table[index] & PT_BASE_ADDR_MASK);
+               kunmap_atomic(walker->table, KM_USER0);
+               walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT),
+                                           KM_USER0);
+               --walker->level;
+       }
+}
+
+/*
+ * Fetch a shadow pte for a specific level in the paging hierarchy.
+ */
+static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
+                             struct guest_walker *walker)
+{
+       hpa_t shadow_addr;
+       int level;
+       u64 *prev_shadow_ent = NULL;
+
+       shadow_addr = vcpu->mmu.root_hpa;
+       level = vcpu->mmu.shadow_root_level;
+
+       for (; ; level--) {
+               u32 index = SHADOW_PT_INDEX(addr, level);
+               u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index;
+               pt_element_t *guest_ent;
+
+               if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
+                       if (level == PT_PAGE_TABLE_LEVEL)
+                               return shadow_ent;
+                       shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
+                       prev_shadow_ent = shadow_ent;
+                       continue;
+               }
+
+               if (PTTYPE == 32 && level > PT32_ROOT_LEVEL) {
+                       ASSERT(level == PT32E_ROOT_LEVEL);
+                       guest_ent = FNAME(fetch_guest)(vcpu, walker,
+                                                      PT32_ROOT_LEVEL, addr);
+               } else
+                       guest_ent = FNAME(fetch_guest)(vcpu, walker,
+                                                      level, addr);
+
+               if (!is_present_pte(*guest_ent))
+                       return NULL;
+
+               /* Don't set accessed bit on PAE PDPTRs */
+               if (vcpu->mmu.root_level != 3 || walker->level != 3)
+                       *guest_ent |= PT_ACCESSED_MASK;
+
+               if (level == PT_PAGE_TABLE_LEVEL) {
+
+                       if (walker->level == PT_DIRECTORY_LEVEL) {
+                               if (prev_shadow_ent)
+                                       *prev_shadow_ent |= PT_SHADOW_PS_MARK;
+                               FNAME(set_pde)(vcpu, *guest_ent, shadow_ent,
+                                              walker->inherited_ar,
+                                         PT_INDEX(addr, PT_PAGE_TABLE_LEVEL));
+                       } else {
+                               ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
+                               FNAME(set_pte)(vcpu, *guest_ent, shadow_ent, walker->inherited_ar);
+                       }
+                       return shadow_ent;
+               }
+
+               shadow_addr = kvm_mmu_alloc_page(vcpu, shadow_ent);
+               if (!VALID_PAGE(shadow_addr))
+                       return ERR_PTR(-ENOMEM);
+               if (!kvm_arch_ops->is_long_mode(vcpu) && level == 3)
+                       *shadow_ent = shadow_addr |
+                               (*guest_ent & (PT_PRESENT_MASK | PT_PWT_MASK | PT_PCD_MASK));
+               else {
+                       *shadow_ent = shadow_addr |
+                               (*guest_ent & PT_NON_PTE_COPY_MASK);
+                       *shadow_ent |= (PT_WRITABLE_MASK | PT_USER_MASK);
+               }
+               prev_shadow_ent = shadow_ent;
+       }
+}
+
+/*
+ * The guest faulted for write.  We need to
+ *
+ * - check write permissions
+ * - update the guest pte dirty bit
+ * - update our own dirty page tracking structures
+ */
+static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
+                              u64 *shadow_ent,
+                              struct guest_walker *walker,
+                              gva_t addr,
+                              int user)
+{
+       pt_element_t *guest_ent;
+       int writable_shadow;
+       gfn_t gfn;
+
+       if (is_writeble_pte(*shadow_ent))
+               return 0;
+
+       writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK;
+       if (user) {
+               /*
+                * User mode access.  Fail if it's a kernel page or a read-only
+                * page.
+                */
+               if (!(*shadow_ent & PT_SHADOW_USER_MASK) || !writable_shadow)
+                       return 0;
+               ASSERT(*shadow_ent & PT_USER_MASK);
+       } else
+               /*
+                * Kernel mode access.  Fail if it's a read-only page and
+                * supervisor write protection is enabled.
+                */
+               if (!writable_shadow) {
+                       if (is_write_protection(vcpu))
+                               return 0;
+                       *shadow_ent &= ~PT_USER_MASK;
+               }
+
+       guest_ent = FNAME(fetch_guest)(vcpu, walker, PT_PAGE_TABLE_LEVEL, addr);
+
+       if (!is_present_pte(*guest_ent)) {
+               *shadow_ent = 0;
+               return 0;
+       }
+
+       gfn = (*guest_ent & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
+       mark_page_dirty(vcpu->kvm, gfn);
+       *shadow_ent |= PT_WRITABLE_MASK;
+       *guest_ent |= PT_DIRTY_MASK;
+
+       return 1;
+}
+
+/*
+ * Page fault handler.  There are several causes for a page fault:
+ *   - there is no shadow pte for the guest pte
+ *   - write access through a shadow pte marked read only so that we can set
+ *     the dirty bit
+ *   - write access to a shadow pte marked read only so we can update the page
+ *     dirty bitmap, when userspace requests it
+ *   - mmio access; in this case we will never install a present shadow pte
+ *   - normal guest page fault due to the guest pte marked not present, not
+ *     writable, or not executable
+ *
+ *  Returns: 1 if we need to emulate the instruction, 0 otherwise
+ */
+static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
+                              u32 error_code)
+{
+       int write_fault = error_code & PFERR_WRITE_MASK;
+       int pte_present = error_code & PFERR_PRESENT_MASK;
+       int user_fault = error_code & PFERR_USER_MASK;
+       struct guest_walker walker;
+       u64 *shadow_pte;
+       int fixed;
+
+       /*
+        * Look up the shadow pte for the faulting address.
+        */
+       for (;;) {
+               FNAME(init_walker)(&walker, vcpu);
+               shadow_pte = FNAME(fetch)(vcpu, addr, &walker);
+               if (IS_ERR(shadow_pte)) {  /* must be -ENOMEM */
+                       nonpaging_flush(vcpu);
+                       FNAME(release_walker)(&walker);
+                       continue;
+               }
+               break;
+       }
+
+       /*
+        * The page is not mapped by the guest.  Let the guest handle it.
+        */
+       if (!shadow_pte) {
+               inject_page_fault(vcpu, addr, error_code);
+               FNAME(release_walker)(&walker);
+               return 0;
+       }
+
+       /*
+        * Update the shadow pte.
+        */
+       if (write_fault)
+               fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr,
+                                           user_fault);
+       else
+               fixed = fix_read_pf(shadow_pte);
+
+       FNAME(release_walker)(&walker);
+
+       /*
+        * mmio: emulate if accessible, otherwise its a guest fault.
+        */
+       if (is_io_pte(*shadow_pte)) {
+               if (may_access(*shadow_pte, write_fault, user_fault))
+                       return 1;
+               pgprintk("%s: io work, no access\n", __FUNCTION__);
+               inject_page_fault(vcpu, addr,
+                                 error_code | PFERR_PRESENT_MASK);
+               return 0;
+       }
+
+       /*
+        * pte not present, guest page fault.
+        */
+       if (pte_present && !fixed) {
+               inject_page_fault(vcpu, addr, error_code);
+               return 0;
+       }
+
+       ++kvm_stat.pf_fixed;
+
+       return 0;
+}
+
+static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
+{
+       struct guest_walker walker;
+       pt_element_t guest_pte;
+       gpa_t gpa;
+
+       FNAME(init_walker)(&walker, vcpu);
+       guest_pte = *FNAME(fetch_guest)(vcpu, &walker, PT_PAGE_TABLE_LEVEL,
+                                       vaddr);
+       FNAME(release_walker)(&walker);
+
+       if (!is_present_pte(guest_pte))
+               return UNMAPPED_GVA;
+
+       if (walker.level == PT_DIRECTORY_LEVEL) {
+               ASSERT((guest_pte & PT_PAGE_SIZE_MASK));
+               ASSERT(PTTYPE == 64 || is_pse(vcpu));
+
+               gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr &
+                       (PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK));
+
+               if (PTTYPE == 32 && is_cpuid_PSE36())
+                       gpa |= (guest_pte & PT32_DIR_PSE36_MASK) <<
+                                       (32 - PT32_DIR_PSE36_SHIFT);
+       } else {
+               gpa = (guest_pte & PT_BASE_ADDR_MASK);
+               gpa |= (vaddr & ~PAGE_MASK);
+       }
+
+       return gpa;
+}
+
+#undef pt_element_t
+#undef guest_walker
+#undef FNAME
+#undef PT_BASE_ADDR_MASK
+#undef PT_INDEX
+#undef SHADOW_PT_INDEX
+#undef PT_LEVEL_MASK
+#undef PT_PTE_COPY_MASK
+#undef PT_NON_PTE_COPY_MASK
+#undef PT_DIR_BASE_ADDR_MASK
diff --git a/drivers/kvm/segment_descriptor.h b/drivers/kvm/segment_descriptor.h
new file mode 100644 (file)
index 0000000..71fdf45
--- /dev/null
@@ -0,0 +1,17 @@
+struct segment_descriptor {
+       u16 limit_low;
+       u16 base_low;
+       u8  base_mid;
+       u8  type : 4;
+       u8  system : 1;
+       u8  dpl : 2;
+       u8  present : 1;
+       u8  limit_high : 4;
+       u8  avl : 1;
+       u8  long_mode : 1;
+       u8  default_op : 1;
+       u8  granularity : 1;
+       u8  base_high;
+} __attribute__((packed));
+
+
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
new file mode 100644 (file)
index 0000000..a33a89c
--- /dev/null
@@ -0,0 +1,1677 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * AMD SVM support
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <asm/desc.h>
+
+#include "kvm_svm.h"
+#include "x86_emulate.h"
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+#define IOPM_ALLOC_ORDER 2
+#define MSRPM_ALLOC_ORDER 1
+
+#define DB_VECTOR 1
+#define UD_VECTOR 6
+#define GP_VECTOR 13
+
+#define DR7_GD_MASK (1 << 13)
+#define DR6_BD_MASK (1 << 13)
+#define CR4_DE_MASK (1UL << 3)
+
+#define SEG_TYPE_LDT 2
+#define SEG_TYPE_BUSY_TSS16 3
+
+#define KVM_EFER_LMA (1 << 10)
+#define KVM_EFER_LME (1 << 8)
+
+unsigned long iopm_base;
+unsigned long msrpm_base;
+
+struct kvm_ldttss_desc {
+       u16 limit0;
+       u16 base0;
+       unsigned base1 : 8, type : 5, dpl : 2, p : 1;
+       unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+       u32 base3;
+       u32 zero1;
+} __attribute__((packed));
+
+struct svm_cpu_data {
+       int cpu;
+
+       uint64_t asid_generation;
+       uint32_t max_asid;
+       uint32_t next_asid;
+       struct kvm_ldttss_desc *tss_desc;
+
+       struct page *save_area;
+};
+
+static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+
+struct svm_init_data {
+       int cpu;
+       int r;
+};
+
+static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
+
+#define NUM_MSR_MAPS (sizeof(msrpm_ranges) / sizeof(*msrpm_ranges))
+#define MSRS_RANGE_SIZE 2048
+#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
+
+#define MAX_INST_SIZE 15
+
+static unsigned get_addr_size(struct kvm_vcpu *vcpu)
+{
+       struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
+       u16 cs_attrib;
+
+       if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM))
+               return 2;
+
+       cs_attrib = sa->cs.attrib;
+
+       return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
+                               (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
+}
+
+static inline u8 pop_irq(struct kvm_vcpu *vcpu)
+{
+       int word_index = __ffs(vcpu->irq_summary);
+       int bit_index = __ffs(vcpu->irq_pending[word_index]);
+       int irq = word_index * BITS_PER_LONG + bit_index;
+
+       clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+       if (!vcpu->irq_pending[word_index])
+               clear_bit(word_index, &vcpu->irq_summary);
+       return irq;
+}
+
+static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
+{
+       set_bit(irq, vcpu->irq_pending);
+       set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+}
+
+static inline void clgi(void)
+{
+       asm volatile (SVM_CLGI);
+}
+
+static inline void stgi(void)
+{
+       asm volatile (SVM_STGI);
+}
+
+static inline void invlpga(unsigned long addr, u32 asid)
+{
+       asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid));
+}
+
+static inline unsigned long kvm_read_cr2(void)
+{
+       unsigned long cr2;
+
+       asm volatile ("mov %%cr2, %0" : "=r" (cr2));
+       return cr2;
+}
+
+static inline void kvm_write_cr2(unsigned long val)
+{
+       asm volatile ("mov %0, %%cr2" :: "r" (val));
+}
+
+static inline unsigned long read_dr6(void)
+{
+       unsigned long dr6;
+
+       asm volatile ("mov %%dr6, %0" : "=r" (dr6));
+       return dr6;
+}
+
+static inline void write_dr6(unsigned long val)
+{
+       asm volatile ("mov %0, %%dr6" :: "r" (val));
+}
+
+static inline unsigned long read_dr7(void)
+{
+       unsigned long dr7;
+
+       asm volatile ("mov %%dr7, %0" : "=r" (dr7));
+       return dr7;
+}
+
+static inline void write_dr7(unsigned long val)
+{
+       asm volatile ("mov %0, %%dr7" :: "r" (val));
+}
+
+static inline int svm_is_long_mode(struct kvm_vcpu *vcpu)
+{
+       return vcpu->svm->vmcb->save.efer & KVM_EFER_LMA;
+}
+
+static inline void force_new_asid(struct kvm_vcpu *vcpu)
+{
+       vcpu->svm->asid_generation--;
+}
+
+static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
+{
+       force_new_asid(vcpu);
+}
+
+static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+       if (!(efer & KVM_EFER_LMA))
+               efer &= ~KVM_EFER_LME;
+
+       vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
+       vcpu->shadow_efer = efer;
+}
+
+static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
+{
+       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+                                               SVM_EVTINJ_VALID_ERR |
+                                               SVM_EVTINJ_TYPE_EXEPT |
+                                               GP_VECTOR;
+       vcpu->svm->vmcb->control.event_inj_err = error_code;
+}
+
+static void inject_ud(struct kvm_vcpu *vcpu)
+{
+       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+                                               SVM_EVTINJ_TYPE_EXEPT |
+                                               UD_VECTOR;
+}
+
+static void inject_db(struct kvm_vcpu *vcpu)
+{
+       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+                                               SVM_EVTINJ_TYPE_EXEPT |
+                                               DB_VECTOR;
+}
+
+static int is_page_fault(uint32_t info)
+{
+       info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
+       return info == (PF_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT);
+}
+
+static int is_external_interrupt(u32 info)
+{
+       info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
+       return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
+}
+
+static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       if (!vcpu->svm->next_rip) {
+               printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
+               return;
+       }
+       if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) {
+               printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
+                      __FUNCTION__,
+                      vcpu->svm->vmcb->save.rip,
+                      vcpu->svm->next_rip);
+       }
+
+       vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
+       vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+}
+
+static int has_svm(void)
+{
+       uint32_t eax, ebx, ecx, edx;
+
+       if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+               printk(KERN_INFO "has_svm: not amd\n");
+               return 0;
+       }
+
+       cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+       if (eax < SVM_CPUID_FUNC) {
+               printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n");
+               return 0;
+       }
+
+       cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+       if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
+               printk(KERN_DEBUG "has_svm: svm not available\n");
+               return 0;
+       }
+       return 1;
+}
+
+static void svm_hardware_disable(void *garbage)
+{
+       struct svm_cpu_data *svm_data
+               = per_cpu(svm_data, raw_smp_processor_id());
+
+       if (svm_data) {
+               uint64_t efer;
+
+               wrmsrl(MSR_VM_HSAVE_PA, 0);
+               rdmsrl(MSR_EFER, efer);
+               wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
+               per_cpu(svm_data, raw_smp_processor_id()) = 0;
+               __free_page(svm_data->save_area);
+               kfree(svm_data);
+       }
+}
+
+static void svm_hardware_enable(void *garbage)
+{
+
+       struct svm_cpu_data *svm_data;
+       uint64_t efer;
+#ifdef __x86_64__
+       struct desc_ptr gdt_descr;
+#else
+       struct Xgt_desc_struct gdt_descr;
+#endif
+       struct desc_struct *gdt;
+       int me = raw_smp_processor_id();
+
+       if (!has_svm()) {
+               printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
+               return;
+       }
+       svm_data = per_cpu(svm_data, me);
+
+       if (!svm_data) {
+               printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
+                      me);
+               return;
+       }
+
+       svm_data->asid_generation = 1;
+       svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
+       svm_data->next_asid = svm_data->max_asid + 1;
+
+       asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
+       gdt = (struct desc_struct *)gdt_descr.address;
+       svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
+
+       rdmsrl(MSR_EFER, efer);
+       wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK);
+
+       wrmsrl(MSR_VM_HSAVE_PA,
+              page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
+}
+
+static int svm_cpu_init(int cpu)
+{
+       struct svm_cpu_data *svm_data;
+       int r;
+
+       svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
+       if (!svm_data)
+               return -ENOMEM;
+       svm_data->cpu = cpu;
+       svm_data->save_area = alloc_page(GFP_KERNEL);
+       r = -ENOMEM;
+       if (!svm_data->save_area)
+               goto err_1;
+
+       per_cpu(svm_data, cpu) = svm_data;
+
+       return 0;
+
+err_1:
+       kfree(svm_data);
+       return r;
+
+}
+
+static int set_msr_interception(u32 *msrpm, unsigned msr,
+                               int read, int write)
+{
+       int i;
+
+       for (i = 0; i < NUM_MSR_MAPS; i++) {
+               if (msr >= msrpm_ranges[i] &&
+                   msr < msrpm_ranges[i] + MSRS_IN_RANGE) {
+                       u32 msr_offset = (i * MSRS_IN_RANGE + msr -
+                                         msrpm_ranges[i]) * 2;
+
+                       u32 *base = msrpm + (msr_offset / 32);
+                       u32 msr_shift = msr_offset % 32;
+                       u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
+                       *base = (*base & ~(0x3 << msr_shift)) |
+                               (mask << msr_shift);
+                       return 1;
+               }
+       }
+       printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr);
+       return 0;
+}
+
+static __init int svm_hardware_setup(void)
+{
+       int cpu;
+       struct page *iopm_pages;
+       struct page *msrpm_pages;
+       void *msrpm_va;
+       int r;
+
+
+       iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
+
+       if (!iopm_pages)
+               return -ENOMEM;
+       memset(page_address(iopm_pages), 0xff,
+                                       PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+       iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
+
+
+       msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
+
+       r = -ENOMEM;
+       if (!msrpm_pages)
+               goto err_1;
+
+       msrpm_va = page_address(msrpm_pages);
+       memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
+       msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT;
+
+#ifdef __x86_64__
+       set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1);
+       set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1);
+       set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1);
+       set_msr_interception(msrpm_va, MSR_STAR, 1, 1);
+       set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1);
+       set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1);
+       set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1);
+#endif
+       set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1);
+       set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1);
+       set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1);
+
+       for_each_online_cpu(cpu) {
+               r = svm_cpu_init(cpu);
+               if (r)
+                       goto err_2;
+       }
+       return 0;
+
+err_2:
+       __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER);
+       msrpm_base = 0;
+err_1:
+       __free_pages(iopm_pages, IOPM_ALLOC_ORDER);
+       iopm_base = 0;
+       return r;
+}
+
+static __exit void svm_hardware_unsetup(void)
+{
+       __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER);
+       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
+       iopm_base = msrpm_base = 0;
+}
+
+static void init_seg(struct vmcb_seg *seg)
+{
+       seg->selector = 0;
+       seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK |
+               SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */
+       seg->limit = 0xffff;
+       seg->base = 0;
+}
+
+static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
+{
+       seg->selector = 0;
+       seg->attrib = SVM_SELECTOR_P_MASK | type;
+       seg->limit = 0xffff;
+       seg->base = 0;
+}
+
+static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+       return 0;
+}
+
+static void init_vmcb(struct vmcb *vmcb)
+{
+       struct vmcb_control_area *control = &vmcb->control;
+       struct vmcb_save_area *save = &vmcb->save;
+       u64 tsc;
+
+       control->intercept_cr_read =    INTERCEPT_CR0_MASK |
+                                       INTERCEPT_CR3_MASK |
+                                       INTERCEPT_CR4_MASK;
+
+       control->intercept_cr_write =   INTERCEPT_CR0_MASK |
+                                       INTERCEPT_CR3_MASK |
+                                       INTERCEPT_CR4_MASK;
+
+       control->intercept_dr_read =    INTERCEPT_DR0_MASK |
+                                       INTERCEPT_DR1_MASK |
+                                       INTERCEPT_DR2_MASK |
+                                       INTERCEPT_DR3_MASK;
+
+       control->intercept_dr_write =   INTERCEPT_DR0_MASK |
+                                       INTERCEPT_DR1_MASK |
+                                       INTERCEPT_DR2_MASK |
+                                       INTERCEPT_DR3_MASK |
+                                       INTERCEPT_DR5_MASK |
+                                       INTERCEPT_DR7_MASK;
+
+       control->intercept_exceptions = 1 << PF_VECTOR;
+
+
+       control->intercept =    (1ULL << INTERCEPT_INTR) |
+                               (1ULL << INTERCEPT_NMI) |
+               /*
+                * selective cr0 intercept bug?
+                *      0:   0f 22 d8                mov    %eax,%cr3
+                *      3:   0f 20 c0                mov    %cr0,%eax
+                *      6:   0d 00 00 00 80          or     $0x80000000,%eax
+                *      b:   0f 22 c0                mov    %eax,%cr0
+                * set cr3 ->interception
+                * get cr0 ->interception
+                * set cr0 -> no interception
+                */
+               /*              (1ULL << INTERCEPT_SELECTIVE_CR0) | */
+                               (1ULL << INTERCEPT_CPUID) |
+                               (1ULL << INTERCEPT_HLT) |
+                               (1ULL << INTERCEPT_INVLPG) |
+                               (1ULL << INTERCEPT_INVLPGA) |
+                               (1ULL << INTERCEPT_IOIO_PROT) |
+                               (1ULL << INTERCEPT_MSR_PROT) |
+                               (1ULL << INTERCEPT_TASK_SWITCH) |
+                               (1ULL << INTERCEPT_VMRUN) |
+                               (1ULL << INTERCEPT_VMMCALL) |
+                               (1ULL << INTERCEPT_VMLOAD) |
+                               (1ULL << INTERCEPT_VMSAVE) |
+                               (1ULL << INTERCEPT_STGI) |
+                               (1ULL << INTERCEPT_CLGI) |
+                               (1ULL << INTERCEPT_SKINIT);
+
+       control->iopm_base_pa = iopm_base;
+       control->msrpm_base_pa = msrpm_base;
+       rdtscll(tsc);
+       control->tsc_offset = -tsc;
+       control->int_ctl = V_INTR_MASKING_MASK;
+
+       init_seg(&save->es);
+       init_seg(&save->ss);
+       init_seg(&save->ds);
+       init_seg(&save->fs);
+       init_seg(&save->gs);
+
+       save->cs.selector = 0xf000;
+       /* Executable/Readable Code Segment */
+       save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK |
+               SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK;
+       save->cs.limit = 0xffff;
+       save->cs.base = 0xffff0000;
+
+       save->gdtr.limit = 0xffff;
+       save->idtr.limit = 0xffff;
+
+       init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
+       init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
+
+       save->efer = MSR_EFER_SVME_MASK;
+
+        save->dr6 = 0xffff0ff0;
+       save->dr7 = 0x400;
+       save->rflags = 2;
+       save->rip = 0x0000fff0;
+
+       /*
+        * cr0 val on cpu init should be 0x60000010, we enable cpu
+        * cache by default. the orderly way is to enable cache in bios.
+        */
+       save->cr0 = 0x00000010 | CR0_PG_MASK;
+       save->cr4 = CR4_PAE_MASK;
+       /* rdx = ?? */
+}
+
+static int svm_create_vcpu(struct kvm_vcpu *vcpu)
+{
+       struct page *page;
+       int r;
+
+       r = -ENOMEM;
+       vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
+       if (!vcpu->svm)
+               goto out1;
+       page = alloc_page(GFP_KERNEL);
+       if (!page)
+               goto out2;
+
+       vcpu->svm->vmcb = page_address(page);
+       memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+       vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
+       vcpu->svm->cr0 = 0x00000010;
+       vcpu->svm->asid_generation = 0;
+       memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
+       init_vmcb(vcpu->svm->vmcb);
+
+       return 0;
+
+out2:
+       kfree(vcpu->svm);
+out1:
+       return r;
+}
+
+static void svm_free_vcpu(struct kvm_vcpu *vcpu)
+{
+       if (!vcpu->svm)
+               return;
+       if (vcpu->svm->vmcb)
+               __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
+       kfree(vcpu->svm);
+}
+
+static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
+{
+       get_cpu();
+       return vcpu;
+}
+
+static void svm_vcpu_put(struct kvm_vcpu *vcpu)
+{
+       put_cpu();
+}
+
+static void svm_cache_regs(struct kvm_vcpu *vcpu)
+{
+       vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
+       vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp;
+       vcpu->rip = vcpu->svm->vmcb->save.rip;
+}
+
+static void svm_decache_regs(struct kvm_vcpu *vcpu)
+{
+       vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
+       vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
+       vcpu->svm->vmcb->save.rip = vcpu->rip;
+}
+
+static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
+{
+       return vcpu->svm->vmcb->save.rflags;
+}
+
+static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+       vcpu->svm->vmcb->save.rflags = rflags;
+}
+
+static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
+{
+       struct vmcb_save_area *save = &vcpu->svm->vmcb->save;
+
+       switch (seg) {
+       case VCPU_SREG_CS: return &save->cs;
+       case VCPU_SREG_DS: return &save->ds;
+       case VCPU_SREG_ES: return &save->es;
+       case VCPU_SREG_FS: return &save->fs;
+       case VCPU_SREG_GS: return &save->gs;
+       case VCPU_SREG_SS: return &save->ss;
+       case VCPU_SREG_TR: return &save->tr;
+       case VCPU_SREG_LDTR: return &save->ldtr;
+       }
+       BUG();
+       return 0;
+}
+
+static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+       struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+       return s->base;
+}
+
+static void svm_get_segment(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg)
+{
+       struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+       var->base = s->base;
+       var->limit = s->limit;
+       var->selector = s->selector;
+       var->type = s->attrib & SVM_SELECTOR_TYPE_MASK;
+       var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1;
+       var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
+       var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1;
+       var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1;
+       var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
+       var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
+       var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1;
+       var->unusable = !var->present;
+}
+
+static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+       struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
+
+       *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
+       *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
+}
+
+static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       dt->limit = vcpu->svm->vmcb->save.ldtr.limit;
+       dt->base = vcpu->svm->vmcb->save.ldtr.base;
+}
+
+static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       vcpu->svm->vmcb->save.ldtr.limit = dt->limit;
+       vcpu->svm->vmcb->save.ldtr.base = dt->base ;
+}
+
+static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       dt->limit = vcpu->svm->vmcb->save.gdtr.limit;
+       dt->base = vcpu->svm->vmcb->save.gdtr.base;
+}
+
+static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       vcpu->svm->vmcb->save.gdtr.limit = dt->limit;
+       vcpu->svm->vmcb->save.gdtr.base = dt->base ;
+}
+
+static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+#ifdef __x86_64__
+       if (vcpu->shadow_efer & KVM_EFER_LME) {
+               if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+                       vcpu->shadow_efer |= KVM_EFER_LMA;
+                       vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
+               }
+
+               if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
+                       vcpu->shadow_efer &= ~KVM_EFER_LMA;
+                       vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
+               }
+       }
+#endif
+       vcpu->svm->cr0 = cr0;
+       vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK;
+       vcpu->cr0 = cr0;
+}
+
+static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+       vcpu->cr4 = cr4;
+       vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK;
+}
+
+static void svm_set_segment(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg)
+{
+       struct vmcb_seg *s = svm_seg(vcpu, seg);
+
+       s->base = var->base;
+       s->limit = var->limit;
+       s->selector = var->selector;
+       if (var->unusable)
+               s->attrib = 0;
+       else {
+               s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
+               s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
+               s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+               s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
+               s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+               s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
+               s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
+               s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
+       }
+       if (seg == VCPU_SREG_CS)
+               vcpu->svm->vmcb->save.cpl
+                       = (vcpu->svm->vmcb->save.cs.attrib
+                          >> SVM_SELECTOR_DPL_SHIFT) & 3;
+
+}
+
+/* FIXME:
+
+       vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
+       vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
+
+*/
+
+static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+{
+       return -EOPNOTSUPP;
+}
+
+static void load_host_msrs(struct kvm_vcpu *vcpu)
+{
+       int i;
+
+       for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
+               wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+}
+
+static void save_host_msrs(struct kvm_vcpu *vcpu)
+{
+       int i;
+
+       for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
+               rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+}
+
+static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
+{
+       if (svm_data->next_asid > svm_data->max_asid) {
+               ++svm_data->asid_generation;
+               svm_data->next_asid = 1;
+               vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
+       }
+
+       vcpu->cpu = svm_data->cpu;
+       vcpu->svm->asid_generation = svm_data->asid_generation;
+       vcpu->svm->vmcb->control.asid = svm_data->next_asid++;
+}
+
+static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
+{
+       invlpga(address, vcpu->svm->vmcb->control.asid); // is needed?
+}
+
+static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
+{
+       return vcpu->svm->db_regs[dr];
+}
+
+static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
+                      int *exception)
+{
+       *exception = 0;
+
+       if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) {
+               vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
+               vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK;
+               *exception = DB_VECTOR;
+               return;
+       }
+
+       switch (dr) {
+       case 0 ... 3:
+               vcpu->svm->db_regs[dr] = value;
+               return;
+       case 4 ... 5:
+               if (vcpu->cr4 & CR4_DE_MASK) {
+                       *exception = UD_VECTOR;
+                       return;
+               }
+       case 7: {
+               if (value & ~((1ULL << 32) - 1)) {
+                       *exception = GP_VECTOR;
+                       return;
+               }
+               vcpu->svm->vmcb->save.dr7 = value;
+               return;
+       }
+       default:
+               printk(KERN_DEBUG "%s: unexpected dr %u\n",
+                      __FUNCTION__, dr);
+               *exception = UD_VECTOR;
+               return;
+       }
+}
+
+static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+       u64 fault_address;
+       u32 error_code;
+       enum emulation_result er;
+
+       if (is_external_interrupt(exit_int_info))
+               push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+
+       spin_lock(&vcpu->kvm->lock);
+
+       fault_address  = vcpu->svm->vmcb->control.exit_info_2;
+       error_code = vcpu->svm->vmcb->control.exit_info_1;
+       if (!vcpu->mmu.page_fault(vcpu, fault_address, error_code)) {
+               spin_unlock(&vcpu->kvm->lock);
+               return 1;
+       }
+       er = emulate_instruction(vcpu, kvm_run, fault_address, error_code);
+       spin_unlock(&vcpu->kvm->lock);
+
+       switch (er) {
+       case EMULATE_DONE:
+               return 1;
+       case EMULATE_DO_MMIO:
+               ++kvm_stat.mmio_exits;
+               kvm_run->exit_reason = KVM_EXIT_MMIO;
+               return 0;
+       case EMULATE_FAIL:
+               vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+               break;
+       default:
+               BUG();
+       }
+
+       kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+       return 0;
+}
+
+static int io_get_override(struct kvm_vcpu *vcpu,
+                         struct vmcb_seg **seg,
+                         int *addr_override)
+{
+       u8 inst[MAX_INST_SIZE];
+       unsigned ins_length;
+       gva_t rip;
+       int i;
+
+       rip =  vcpu->svm->vmcb->save.rip;
+       ins_length = vcpu->svm->next_rip - rip;
+       rip += vcpu->svm->vmcb->save.cs.base;
+
+       if (ins_length > MAX_INST_SIZE)
+               printk(KERN_DEBUG
+                      "%s: inst length err, cs base 0x%llx rip 0x%llx "
+                      "next rip 0x%llx ins_length %u\n",
+                      __FUNCTION__,
+                      vcpu->svm->vmcb->save.cs.base,
+                      vcpu->svm->vmcb->save.rip,
+                      vcpu->svm->vmcb->control.exit_info_2,
+                      ins_length);
+
+       if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length)
+               /* #PF */
+               return 0;
+
+       *addr_override = 0;
+       *seg = 0;
+       for (i = 0; i < ins_length; i++)
+               switch (inst[i]) {
+               case 0xf0:
+               case 0xf2:
+               case 0xf3:
+               case 0x66:
+                       continue;
+               case 0x67:
+                       *addr_override = 1;
+                       continue;
+               case 0x2e:
+                       *seg = &vcpu->svm->vmcb->save.cs;
+                       continue;
+               case 0x36:
+                       *seg = &vcpu->svm->vmcb->save.ss;
+                       continue;
+               case 0x3e:
+                       *seg = &vcpu->svm->vmcb->save.ds;
+                       continue;
+               case 0x26:
+                       *seg = &vcpu->svm->vmcb->save.es;
+                       continue;
+               case 0x64:
+                       *seg = &vcpu->svm->vmcb->save.fs;
+                       continue;
+               case 0x65:
+                       *seg = &vcpu->svm->vmcb->save.gs;
+                       continue;
+               default:
+                       return 1;
+               }
+       printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
+       return 0;
+}
+
+static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address)
+{
+       unsigned long addr_mask;
+       unsigned long *reg;
+       struct vmcb_seg *seg;
+       int addr_override;
+       struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save;
+       u16 cs_attrib = save_area->cs.attrib;
+       unsigned addr_size = get_addr_size(vcpu);
+
+       if (!io_get_override(vcpu, &seg, &addr_override))
+               return 0;
+
+       if (addr_override)
+               addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
+
+       if (ins) {
+               reg = &vcpu->regs[VCPU_REGS_RDI];
+               seg = &vcpu->svm->vmcb->save.es;
+       } else {
+               reg = &vcpu->regs[VCPU_REGS_RSI];
+               seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds;
+       }
+
+       addr_mask = ~0ULL >> (64 - (addr_size * 8));
+
+       if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
+           !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
+               *address = (*reg & addr_mask);
+               return addr_mask;
+       }
+
+       if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
+               svm_inject_gp(vcpu, 0);
+               return 0;
+       }
+
+       *address = (*reg & addr_mask) + seg->base;
+       return addr_mask;
+}
+
+static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
+       int _in = io_info & SVM_IOIO_TYPE_MASK;
+
+       ++kvm_stat.io_exits;
+
+       vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
+
+       kvm_run->exit_reason = KVM_EXIT_IO;
+       kvm_run->io.port = io_info >> 16;
+       kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+       kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT);
+       kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0;
+       kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+
+       if (kvm_run->io.string) {
+               unsigned addr_mask;
+
+               addr_mask = io_adress(vcpu, _in, &kvm_run->io.address);
+               if (!addr_mask) {
+                       printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__);
+                       return 1;
+               }
+
+               if (kvm_run->io.rep) {
+                       kvm_run->io.count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
+                       kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags
+                                                  & X86_EFLAGS_DF) != 0;
+               }
+       } else {
+               kvm_run->io.value = vcpu->svm->vmcb->save.rax;
+       }
+       return 0;
+}
+
+
+static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       return 1;
+}
+
+static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
+       skip_emulated_instruction(vcpu);
+       if (vcpu->irq_summary && (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF))
+               return 1;
+
+       kvm_run->exit_reason = KVM_EXIT_HLT;
+       return 0;
+}
+
+static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       inject_ud(vcpu);
+       return 1;
+}
+
+static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__);
+       kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+       return 0;
+}
+
+static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+       kvm_run->exit_reason = KVM_EXIT_CPUID;
+       return 0;
+}
+
+static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE)
+               printk(KERN_ERR "%s: failed\n", __FUNCTION__);
+       return 1;
+}
+
+static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
+{
+       switch (ecx) {
+       case MSR_IA32_MC0_CTL:
+       case MSR_IA32_MCG_STATUS:
+       case MSR_IA32_MCG_CAP:
+       case MSR_IA32_MC0_MISC:
+       case MSR_IA32_MC0_MISC+4:
+       case MSR_IA32_MC0_MISC+8:
+       case MSR_IA32_MC0_MISC+12:
+       case MSR_IA32_MC0_MISC+16:
+       case MSR_IA32_UCODE_REV:
+               /* MTRR registers */
+       case 0xfe:
+       case 0x200 ... 0x2ff:
+               *data = 0;
+               break;
+       case MSR_IA32_TIME_STAMP_COUNTER: {
+               u64 tsc;
+
+               rdtscll(tsc);
+               *data = vcpu->svm->vmcb->control.tsc_offset + tsc;
+               break;
+       }
+       case MSR_EFER:
+               *data = vcpu->shadow_efer;
+               break;
+       case MSR_IA32_APICBASE:
+               *data = vcpu->apic_base;
+               break;
+#ifdef __x86_64__
+       case MSR_STAR:
+               *data = vcpu->svm->vmcb->save.star;
+               break;
+       case MSR_LSTAR:
+               *data = vcpu->svm->vmcb->save.lstar;
+               break;
+       case MSR_CSTAR:
+               *data = vcpu->svm->vmcb->save.cstar;
+               break;
+       case MSR_KERNEL_GS_BASE:
+               *data = vcpu->svm->vmcb->save.kernel_gs_base;
+               break;
+       case MSR_SYSCALL_MASK:
+               *data = vcpu->svm->vmcb->save.sfmask;
+               break;
+#endif
+       case MSR_IA32_SYSENTER_CS:
+               *data = vcpu->svm->vmcb->save.sysenter_cs;
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               *data = vcpu->svm->vmcb->save.sysenter_eip;
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               *data = vcpu->svm->vmcb->save.sysenter_esp;
+               break;
+       default:
+               printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", ecx);
+               return 1;
+       }
+       return 0;
+}
+
+static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+       u64 data;
+
+       if (svm_get_msr(vcpu, ecx, &data))
+               svm_inject_gp(vcpu, 0);
+       else {
+               vcpu->svm->vmcb->save.rax = data & 0xffffffff;
+               vcpu->regs[VCPU_REGS_RDX] = data >> 32;
+               vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+               skip_emulated_instruction(vcpu);
+       }
+       return 1;
+}
+
+static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
+{
+       switch (ecx) {
+#ifdef __x86_64__
+       case MSR_EFER:
+               set_efer(vcpu, data);
+               break;
+#endif
+       case MSR_IA32_MC0_STATUS:
+               printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n"
+                           , __FUNCTION__, data);
+               break;
+       case MSR_IA32_TIME_STAMP_COUNTER: {
+               u64 tsc;
+
+               rdtscll(tsc);
+               vcpu->svm->vmcb->control.tsc_offset = data - tsc;
+               break;
+       }
+       case MSR_IA32_UCODE_REV:
+       case MSR_IA32_UCODE_WRITE:
+       case 0x200 ... 0x2ff: /* MTRRs */
+               break;
+       case MSR_IA32_APICBASE:
+               vcpu->apic_base = data;
+               break;
+#ifdef __x86_64___
+       case MSR_STAR:
+               vcpu->svm->vmcb->save.star = data;
+               break;
+       case MSR_LSTAR:
+               vcpu->svm->vmcb->save.lstar = data;
+               break;
+       case MSR_CSTAR:
+               vcpu->svm->vmcb->save.cstar = data;
+               break;
+       case MSR_KERNEL_GS_BASE:
+               vcpu->svm->vmcb->save.kernel_gs_base = data;
+               break;
+       case MSR_SYSCALL_MASK:
+               vcpu->svm->vmcb->save.sfmask = data;
+               break;
+#endif
+       case MSR_IA32_SYSENTER_CS:
+               vcpu->svm->vmcb->save.sysenter_cs = data;
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               vcpu->svm->vmcb->save.sysenter_eip = data;
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               vcpu->svm->vmcb->save.sysenter_esp = data;
+               break;
+       default:
+               printk(KERN_ERR "kvm: unhandled wrmsr: %x\n", ecx);
+               return 1;
+       }
+       return 0;
+}
+
+static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+       u64 data = (vcpu->svm->vmcb->save.rax & -1u)
+               | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
+       vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
+       if (svm_set_msr(vcpu, ecx, data))
+               svm_inject_gp(vcpu, 0);
+       else
+               skip_emulated_instruction(vcpu);
+       return 1;
+}
+
+static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       if (vcpu->svm->vmcb->control.exit_info_1)
+               return wrmsr_interception(vcpu, kvm_run);
+       else
+               return rdmsr_interception(vcpu, kvm_run);
+}
+
+static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
+                                     struct kvm_run *kvm_run) = {
+       [SVM_EXIT_READ_CR0]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR3]                     = emulate_on_interception,
+       [SVM_EXIT_READ_CR4]                     = emulate_on_interception,
+       /* for now: */
+       [SVM_EXIT_WRITE_CR0]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR3]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_CR4]                    = emulate_on_interception,
+       [SVM_EXIT_READ_DR0]                     = emulate_on_interception,
+       [SVM_EXIT_READ_DR1]                     = emulate_on_interception,
+       [SVM_EXIT_READ_DR2]                     = emulate_on_interception,
+       [SVM_EXIT_READ_DR3]                     = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR0]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR1]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR2]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR3]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR5]                    = emulate_on_interception,
+       [SVM_EXIT_WRITE_DR7]                    = emulate_on_interception,
+       [SVM_EXIT_EXCP_BASE + PF_VECTOR]        = pf_interception,
+       [SVM_EXIT_INTR]                         = nop_on_interception,
+       [SVM_EXIT_NMI]                          = nop_on_interception,
+       [SVM_EXIT_SMI]                          = nop_on_interception,
+       [SVM_EXIT_INIT]                         = nop_on_interception,
+       /* [SVM_EXIT_CR0_SEL_WRITE]             = emulate_on_interception, */
+       [SVM_EXIT_CPUID]                        = cpuid_interception,
+       [SVM_EXIT_HLT]                          = halt_interception,
+       [SVM_EXIT_INVLPG]                       = emulate_on_interception,
+       [SVM_EXIT_INVLPGA]                      = invalid_op_interception,
+       [SVM_EXIT_IOIO]                         = io_interception,
+       [SVM_EXIT_MSR]                          = msr_interception,
+       [SVM_EXIT_TASK_SWITCH]                  = task_switch_interception,
+       [SVM_EXIT_VMRUN]                        = invalid_op_interception,
+       [SVM_EXIT_VMMCALL]                      = invalid_op_interception,
+       [SVM_EXIT_VMLOAD]                       = invalid_op_interception,
+       [SVM_EXIT_VMSAVE]                       = invalid_op_interception,
+       [SVM_EXIT_STGI]                         = invalid_op_interception,
+       [SVM_EXIT_CLGI]                         = invalid_op_interception,
+       [SVM_EXIT_SKINIT]                       = invalid_op_interception,
+};
+
+
+static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 exit_code = vcpu->svm->vmcb->control.exit_code;
+
+       kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
+
+       if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
+           exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
+               printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
+                      "exit_code 0x%x\n",
+                      __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
+                      exit_code);
+
+       if (exit_code >= sizeof(svm_exit_handlers) / sizeof(*svm_exit_handlers)
+           || svm_exit_handlers[exit_code] == 0) {
+               kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+               printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n",
+                      __FUNCTION__,
+                      exit_code,
+                      vcpu->svm->vmcb->save.rip,
+                      vcpu->cr0,
+                      vcpu->svm->vmcb->save.rflags);
+               return 0;
+       }
+
+       return svm_exit_handlers[exit_code](vcpu, kvm_run);
+}
+
+static void reload_tss(struct kvm_vcpu *vcpu)
+{
+       int cpu = raw_smp_processor_id();
+
+       struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
+       svm_data->tss_desc->type = 9; //available 32/64-bit TSS
+       load_TR_desc();
+}
+
+static void pre_svm_run(struct kvm_vcpu *vcpu)
+{
+       int cpu = raw_smp_processor_id();
+
+       struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
+
+       vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+       if (vcpu->cpu != cpu ||
+           vcpu->svm->asid_generation != svm_data->asid_generation)
+               new_asid(vcpu, svm_data);
+}
+
+
+static inline void kvm_try_inject_irq(struct kvm_vcpu *vcpu)
+{
+       struct vmcb_control_area *control;
+
+       if (!vcpu->irq_summary)
+               return;
+
+       control = &vcpu->svm->vmcb->control;
+
+       control->int_vector = pop_irq(vcpu);
+       control->int_ctl &= ~V_INTR_PRIO_MASK;
+       control->int_ctl |= V_IRQ_MASK |
+               ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
+}
+
+static void kvm_reput_irq(struct kvm_vcpu *vcpu)
+{
+       struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+
+       if (control->int_ctl & V_IRQ_MASK) {
+               control->int_ctl &= ~V_IRQ_MASK;
+               push_irq(vcpu, control->int_vector);
+       }
+}
+
+static void save_db_regs(unsigned long *db_regs)
+{
+#ifdef __x86_64__
+       asm ("mov %%dr0, %%rax \n\t"
+            "mov %%rax, %[dr0] \n\t"
+            "mov %%dr1, %%rax \n\t"
+            "mov %%rax, %[dr1] \n\t"
+            "mov %%dr2, %%rax \n\t"
+            "mov %%rax, %[dr2] \n\t"
+            "mov %%dr3, %%rax \n\t"
+            "mov %%rax, %[dr3] \n\t"
+            : [dr0] "=m"(db_regs[0]),
+              [dr1] "=m"(db_regs[1]),
+              [dr2] "=m"(db_regs[2]),
+              [dr3] "=m"(db_regs[3])
+            : : "rax");
+#else
+       asm ("mov %%dr0, %%eax \n\t"
+            "mov %%eax, %[dr0] \n\t"
+            "mov %%dr1, %%eax \n\t"
+            "mov %%eax, %[dr1] \n\t"
+            "mov %%dr2, %%eax \n\t"
+            "mov %%eax, %[dr2] \n\t"
+            "mov %%dr3, %%eax \n\t"
+            "mov %%eax, %[dr3] \n\t"
+            : [dr0] "=m"(db_regs[0]),
+              [dr1] "=m"(db_regs[1]),
+              [dr2] "=m"(db_regs[2]),
+              [dr3] "=m"(db_regs[3])
+            : : "eax");
+#endif
+}
+
+static void load_db_regs(unsigned long *db_regs)
+{
+       asm volatile ("mov %[dr0], %%dr0 \n\t"
+            "mov %[dr1], %%dr1 \n\t"
+            "mov %[dr2], %%dr2 \n\t"
+            "mov %[dr3], %%dr3 \n\t"
+            :
+            : [dr0] "r"(db_regs[0]),
+              [dr1] "r"(db_regs[1]),
+              [dr2] "r"(db_regs[2]),
+              [dr3] "r"(db_regs[3])
+#ifdef __x86_64__
+            : "rax");
+#else
+            : "eax");
+#endif
+}
+
+static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u16 fs_selector;
+       u16 gs_selector;
+       u16 ldt_selector;
+
+again:
+       kvm_try_inject_irq(vcpu);
+
+       clgi();
+
+       pre_svm_run(vcpu);
+
+       save_host_msrs(vcpu);
+       fs_selector = read_fs();
+       gs_selector = read_gs();
+       ldt_selector = read_ldt();
+       vcpu->svm->host_cr2 = kvm_read_cr2();
+       vcpu->svm->host_dr6 = read_dr6();
+       vcpu->svm->host_dr7 = read_dr7();
+       vcpu->svm->vmcb->save.cr2 = vcpu->cr2;
+
+       if (vcpu->svm->vmcb->save.dr7 & 0xff) {
+               write_dr7(0);
+               save_db_regs(vcpu->svm->host_db_regs);
+               load_db_regs(vcpu->svm->db_regs);
+       }
+       asm volatile (
+#ifdef __x86_64__
+               "push %%rbx; push %%rcx; push %%rdx;"
+               "push %%rsi; push %%rdi; push %%rbp;"
+               "push %%r8;  push %%r9;  push %%r10; push %%r11;"
+               "push %%r12; push %%r13; push %%r14; push %%r15;"
+#else
+               "push %%ebx; push %%ecx; push %%edx;"
+               "push %%esi; push %%edi; push %%ebp;"
+#endif
+
+#ifdef __x86_64__
+               "mov %c[rbx](%[vcpu]), %%rbx \n\t"
+               "mov %c[rcx](%[vcpu]), %%rcx \n\t"
+               "mov %c[rdx](%[vcpu]), %%rdx \n\t"
+               "mov %c[rsi](%[vcpu]), %%rsi \n\t"
+               "mov %c[rdi](%[vcpu]), %%rdi \n\t"
+               "mov %c[rbp](%[vcpu]), %%rbp \n\t"
+               "mov %c[r8](%[vcpu]),  %%r8  \n\t"
+               "mov %c[r9](%[vcpu]),  %%r9  \n\t"
+               "mov %c[r10](%[vcpu]), %%r10 \n\t"
+               "mov %c[r11](%[vcpu]), %%r11 \n\t"
+               "mov %c[r12](%[vcpu]), %%r12 \n\t"
+               "mov %c[r13](%[vcpu]), %%r13 \n\t"
+               "mov %c[r14](%[vcpu]), %%r14 \n\t"
+               "mov %c[r15](%[vcpu]), %%r15 \n\t"
+#else
+               "mov %c[rbx](%[vcpu]), %%ebx \n\t"
+               "mov %c[rcx](%[vcpu]), %%ecx \n\t"
+               "mov %c[rdx](%[vcpu]), %%edx \n\t"
+               "mov %c[rsi](%[vcpu]), %%esi \n\t"
+               "mov %c[rdi](%[vcpu]), %%edi \n\t"
+               "mov %c[rbp](%[vcpu]), %%ebp \n\t"
+#endif
+
+#ifdef __x86_64__
+               /* Enter guest mode */
+               "push %%rax \n\t"
+               "mov %c[svm](%[vcpu]), %%rax \n\t"
+               "mov %c[vmcb](%%rax), %%rax \n\t"
+               SVM_VMLOAD "\n\t"
+               SVM_VMRUN "\n\t"
+               SVM_VMSAVE "\n\t"
+               "pop %%rax \n\t"
+#else
+               /* Enter guest mode */
+               "push %%eax \n\t"
+               "mov %c[svm](%[vcpu]), %%eax \n\t"
+               "mov %c[vmcb](%%eax), %%eax \n\t"
+               SVM_VMLOAD "\n\t"
+               SVM_VMRUN "\n\t"
+               SVM_VMSAVE "\n\t"
+               "pop %%eax \n\t"
+#endif
+
+               /* Save guest registers, load host registers */
+#ifdef __x86_64__
+               "mov %%rbx, %c[rbx](%[vcpu]) \n\t"
+               "mov %%rcx, %c[rcx](%[vcpu]) \n\t"
+               "mov %%rdx, %c[rdx](%[vcpu]) \n\t"
+               "mov %%rsi, %c[rsi](%[vcpu]) \n\t"
+               "mov %%rdi, %c[rdi](%[vcpu]) \n\t"
+               "mov %%rbp, %c[rbp](%[vcpu]) \n\t"
+               "mov %%r8,  %c[r8](%[vcpu]) \n\t"
+               "mov %%r9,  %c[r9](%[vcpu]) \n\t"
+               "mov %%r10, %c[r10](%[vcpu]) \n\t"
+               "mov %%r11, %c[r11](%[vcpu]) \n\t"
+               "mov %%r12, %c[r12](%[vcpu]) \n\t"
+               "mov %%r13, %c[r13](%[vcpu]) \n\t"
+               "mov %%r14, %c[r14](%[vcpu]) \n\t"
+               "mov %%r15, %c[r15](%[vcpu]) \n\t"
+
+               "pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
+               "pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
+               "pop  %%rbp; pop  %%rdi; pop  %%rsi;"
+               "pop  %%rdx; pop  %%rcx; pop  %%rbx; \n\t"
+#else
+               "mov %%ebx, %c[rbx](%[vcpu]) \n\t"
+               "mov %%ecx, %c[rcx](%[vcpu]) \n\t"
+               "mov %%edx, %c[rdx](%[vcpu]) \n\t"
+               "mov %%esi, %c[rsi](%[vcpu]) \n\t"
+               "mov %%edi, %c[rdi](%[vcpu]) \n\t"
+               "mov %%ebp, %c[rbp](%[vcpu]) \n\t"
+
+               "pop  %%ebp; pop  %%edi; pop  %%esi;"
+               "pop  %%edx; pop  %%ecx; pop  %%ebx; \n\t"
+#endif
+               :
+               : [vcpu]"a"(vcpu),
+                 [svm]"i"(offsetof(struct kvm_vcpu, svm)),
+                 [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
+                 [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
+                 [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
+                 [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
+                 [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
+                 [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
+                 [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP]))
+#ifdef __x86_64__
+                 ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
+                 [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
+                 [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
+                 [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
+                 [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
+                 [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
+                 [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
+                 [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15]))
+#endif
+               : "cc", "memory" );
+
+       if ((vcpu->svm->vmcb->save.dr7 & 0xff))
+               load_db_regs(vcpu->svm->host_db_regs);
+
+       vcpu->cr2 = vcpu->svm->vmcb->save.cr2;
+
+       write_dr6(vcpu->svm->host_dr6);
+       write_dr7(vcpu->svm->host_dr7);
+       kvm_write_cr2(vcpu->svm->host_cr2);
+
+       load_fs(fs_selector);
+       load_gs(gs_selector);
+       load_ldt(ldt_selector);
+       load_host_msrs(vcpu);
+
+       reload_tss(vcpu);
+
+       stgi();
+
+       kvm_reput_irq(vcpu);
+
+       vcpu->svm->next_rip = 0;
+
+       if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+               kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
+               kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code;
+               return 0;
+       }
+
+       if (handle_exit(vcpu, kvm_run)) {
+               if (signal_pending(current)) {
+                       ++kvm_stat.signal_exits;
+                       return -EINTR;
+               }
+               kvm_resched(vcpu);
+               goto again;
+       }
+       return 0;
+}
+
+static void svm_flush_tlb(struct kvm_vcpu *vcpu)
+{
+       force_new_asid(vcpu);
+}
+
+static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
+{
+       vcpu->svm->vmcb->save.cr3 = root;
+       force_new_asid(vcpu);
+}
+
+static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
+                                 unsigned long  addr,
+                                 uint32_t err_code)
+{
+       uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+
+       ++kvm_stat.pf_guest;
+
+       if (is_page_fault(exit_int_info)) {
+
+               vcpu->svm->vmcb->control.event_inj_err = 0;
+               vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+                                                       SVM_EVTINJ_VALID_ERR |
+                                                       SVM_EVTINJ_TYPE_EXEPT |
+                                                       DF_VECTOR;
+               return;
+       }
+       vcpu->cr2 = addr;
+       vcpu->svm->vmcb->save.cr2 = addr;
+       vcpu->svm->vmcb->control.event_inj =    SVM_EVTINJ_VALID |
+                                               SVM_EVTINJ_VALID_ERR |
+                                               SVM_EVTINJ_TYPE_EXEPT |
+                                               PF_VECTOR;
+       vcpu->svm->vmcb->control.event_inj_err = err_code;
+}
+
+
+static int is_disabled(void)
+{
+       return 0;
+}
+
+static struct kvm_arch_ops svm_arch_ops = {
+       .cpu_has_kvm_support = has_svm,
+       .disabled_by_bios = is_disabled,
+       .hardware_setup = svm_hardware_setup,
+       .hardware_unsetup = svm_hardware_unsetup,
+       .hardware_enable = svm_hardware_enable,
+       .hardware_disable = svm_hardware_disable,
+
+       .vcpu_create = svm_create_vcpu,
+       .vcpu_free = svm_free_vcpu,
+
+       .vcpu_load = svm_vcpu_load,
+       .vcpu_put = svm_vcpu_put,
+
+       .set_guest_debug = svm_guest_debug,
+       .get_msr = svm_get_msr,
+       .set_msr = svm_set_msr,
+       .get_segment_base = svm_get_segment_base,
+       .get_segment = svm_get_segment,
+       .set_segment = svm_set_segment,
+       .is_long_mode = svm_is_long_mode,
+       .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+       .set_cr0 = svm_set_cr0,
+       .set_cr0_no_modeswitch = svm_set_cr0,
+       .set_cr3 = svm_set_cr3,
+       .set_cr4 = svm_set_cr4,
+       .set_efer = svm_set_efer,
+       .get_idt = svm_get_idt,
+       .set_idt = svm_set_idt,
+       .get_gdt = svm_get_gdt,
+       .set_gdt = svm_set_gdt,
+       .get_dr = svm_get_dr,
+       .set_dr = svm_set_dr,
+       .cache_regs = svm_cache_regs,
+       .decache_regs = svm_decache_regs,
+       .get_rflags = svm_get_rflags,
+       .set_rflags = svm_set_rflags,
+
+       .invlpg = svm_invlpg,
+       .tlb_flush = svm_flush_tlb,
+       .inject_page_fault = svm_inject_page_fault,
+
+       .inject_gp = svm_inject_gp,
+
+       .run = svm_vcpu_run,
+       .skip_emulated_instruction = skip_emulated_instruction,
+       .vcpu_setup = svm_vcpu_setup,
+};
+
+static int __init svm_init(void)
+{
+       kvm_emulator_want_group7_invlpg();
+       kvm_init_arch(&svm_arch_ops, THIS_MODULE);
+       return 0;
+}
+
+static void __exit svm_exit(void)
+{
+       kvm_exit_arch();
+}
+
+module_init(svm_init)
+module_exit(svm_exit)
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
new file mode 100644 (file)
index 0000000..df731c3
--- /dev/null
@@ -0,0 +1,315 @@
+#ifndef __SVM_H
+#define __SVM_H
+
+enum {
+       INTERCEPT_INTR,
+       INTERCEPT_NMI,
+       INTERCEPT_SMI,
+       INTERCEPT_INIT,
+       INTERCEPT_VINTR,
+       INTERCEPT_SELECTIVE_CR0,
+       INTERCEPT_STORE_IDTR,
+       INTERCEPT_STORE_GDTR,
+       INTERCEPT_STORE_LDTR,
+       INTERCEPT_STORE_TR,
+       INTERCEPT_LOAD_IDTR,
+       INTERCEPT_LOAD_GDTR,
+       INTERCEPT_LOAD_LDTR,
+       INTERCEPT_LOAD_TR,
+       INTERCEPT_RDTSC,
+       INTERCEPT_RDPMC,
+       INTERCEPT_PUSHF,
+       INTERCEPT_POPF,
+       INTERCEPT_CPUID,
+       INTERCEPT_RSM,
+       INTERCEPT_IRET,
+       INTERCEPT_INTn,
+       INTERCEPT_INVD,
+       INTERCEPT_PAUSE,
+       INTERCEPT_HLT,
+       INTERCEPT_INVLPG,
+       INTERCEPT_INVLPGA,
+       INTERCEPT_IOIO_PROT,
+       INTERCEPT_MSR_PROT,
+       INTERCEPT_TASK_SWITCH,
+       INTERCEPT_FERR_FREEZE,
+       INTERCEPT_SHUTDOWN,
+       INTERCEPT_VMRUN,
+       INTERCEPT_VMMCALL,
+       INTERCEPT_VMLOAD,
+       INTERCEPT_VMSAVE,
+       INTERCEPT_STGI,
+       INTERCEPT_CLGI,
+       INTERCEPT_SKINIT,
+       INTERCEPT_RDTSCP,
+       INTERCEPT_ICEBP,
+       INTERCEPT_WBINVD,
+};
+
+
+struct __attribute__ ((__packed__)) vmcb_control_area {
+       u16 intercept_cr_read;
+       u16 intercept_cr_write;
+       u16 intercept_dr_read;
+       u16 intercept_dr_write;
+       u32 intercept_exceptions;
+       u64 intercept;
+       u8 reserved_1[44];
+       u64 iopm_base_pa;
+       u64 msrpm_base_pa;
+       u64 tsc_offset;
+       u32 asid;
+       u8 tlb_ctl;
+       u8 reserved_2[3];
+       u32 int_ctl;
+       u32 int_vector;
+       u32 int_state;
+       u8 reserved_3[4];
+       u32 exit_code;
+       u32 exit_code_hi;
+       u64 exit_info_1;
+       u64 exit_info_2;
+       u32 exit_int_info;
+       u32 exit_int_info_err;
+       u64 nested_ctl;
+       u8 reserved_4[16];
+       u32 event_inj;
+       u32 event_inj_err;
+       u64 nested_cr3;
+       u64 lbr_ctl;
+       u8 reserved_5[832];
+};
+
+
+#define TLB_CONTROL_DO_NOTHING 0
+#define TLB_CONTROL_FLUSH_ALL_ASID 1
+
+#define V_TPR_MASK 0x0f
+
+#define V_IRQ_SHIFT 8
+#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
+
+#define V_INTR_PRIO_SHIFT 16
+#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
+
+#define V_IGN_TPR_SHIFT 20
+#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
+
+#define V_INTR_MASKING_SHIFT 24
+#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
+
+#define SVM_INTERRUPT_SHADOW_MASK 1
+
+#define SVM_IOIO_STR_SHIFT 2
+#define SVM_IOIO_REP_SHIFT 3
+#define SVM_IOIO_SIZE_SHIFT 4
+#define SVM_IOIO_ASIZE_SHIFT 7
+
+#define SVM_IOIO_TYPE_MASK 1
+#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
+#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
+#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
+#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
+
+struct __attribute__ ((__packed__)) vmcb_seg {
+       u16 selector;
+       u16 attrib;
+       u32 limit;
+       u64 base;
+};
+
+struct __attribute__ ((__packed__)) vmcb_save_area {
+       struct vmcb_seg es;
+       struct vmcb_seg cs;
+       struct vmcb_seg ss;
+       struct vmcb_seg ds;
+       struct vmcb_seg fs;
+       struct vmcb_seg gs;
+       struct vmcb_seg gdtr;
+       struct vmcb_seg ldtr;
+       struct vmcb_seg idtr;
+       struct vmcb_seg tr;
+       u8 reserved_1[43];
+       u8 cpl;
+       u8 reserved_2[4];
+       u64 efer;
+       u8 reserved_3[112];
+       u64 cr4;
+       u64 cr3;
+       u64 cr0;
+       u64 dr7;
+       u64 dr6;
+       u64 rflags;
+       u64 rip;
+       u8 reserved_4[88];
+       u64 rsp;
+       u8 reserved_5[24];
+       u64 rax;
+       u64 star;
+       u64 lstar;
+       u64 cstar;
+       u64 sfmask;
+       u64 kernel_gs_base;
+       u64 sysenter_cs;
+       u64 sysenter_esp;
+       u64 sysenter_eip;
+       u64 cr2;
+       u8 reserved_6[32];
+       u64 g_pat;
+       u64 dbgctl;
+       u64 br_from;
+       u64 br_to;
+       u64 last_excp_from;
+       u64 last_excp_to;
+};
+
+struct __attribute__ ((__packed__)) vmcb {
+       struct vmcb_control_area control;
+       struct vmcb_save_area save;
+};
+
+#define SVM_CPUID_FEATURE_SHIFT 2
+#define SVM_CPUID_FUNC 0x8000000a
+
+#define MSR_EFER_SVME_MASK (1ULL << 12)
+#define MSR_VM_HSAVE_PA 0xc0010117ULL
+
+#define SVM_SELECTOR_S_SHIFT 4
+#define SVM_SELECTOR_DPL_SHIFT 5
+#define SVM_SELECTOR_P_SHIFT 7
+#define SVM_SELECTOR_AVL_SHIFT 8
+#define SVM_SELECTOR_L_SHIFT 9
+#define SVM_SELECTOR_DB_SHIFT 10
+#define SVM_SELECTOR_G_SHIFT 11
+
+#define SVM_SELECTOR_TYPE_MASK (0xf)
+#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT)
+#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT)
+#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT)
+#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT)
+#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT)
+#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT)
+#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT)
+
+#define SVM_SELECTOR_WRITE_MASK (1 << 1)
+#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK
+#define SVM_SELECTOR_CODE_MASK (1 << 3)
+
+#define INTERCEPT_CR0_MASK 1
+#define INTERCEPT_CR3_MASK (1 << 3)
+#define INTERCEPT_CR4_MASK (1 << 4)
+
+#define INTERCEPT_DR0_MASK 1
+#define INTERCEPT_DR1_MASK (1 << 1)
+#define INTERCEPT_DR2_MASK (1 << 2)
+#define INTERCEPT_DR3_MASK (1 << 3)
+#define INTERCEPT_DR4_MASK (1 << 4)
+#define INTERCEPT_DR5_MASK (1 << 5)
+#define INTERCEPT_DR6_MASK (1 << 6)
+#define INTERCEPT_DR7_MASK (1 << 7)
+
+#define SVM_EVTINJ_VEC_MASK 0xff
+
+#define SVM_EVTINJ_TYPE_SHIFT 8
+#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_VALID (1 << 31)
+#define SVM_EVTINJ_VALID_ERR (1 << 11)
+
+#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+
+#define        SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
+#define        SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
+#define        SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
+#define        SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
+
+#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
+#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+
+#define        SVM_EXIT_READ_CR0       0x000
+#define        SVM_EXIT_READ_CR3       0x003
+#define        SVM_EXIT_READ_CR4       0x004
+#define        SVM_EXIT_READ_CR8       0x008
+#define        SVM_EXIT_WRITE_CR0      0x010
+#define        SVM_EXIT_WRITE_CR3      0x013
+#define        SVM_EXIT_WRITE_CR4      0x014
+#define        SVM_EXIT_WRITE_CR8      0x018
+#define        SVM_EXIT_READ_DR0       0x020
+#define        SVM_EXIT_READ_DR1       0x021
+#define        SVM_EXIT_READ_DR2       0x022
+#define        SVM_EXIT_READ_DR3       0x023
+#define        SVM_EXIT_READ_DR4       0x024
+#define        SVM_EXIT_READ_DR5       0x025
+#define        SVM_EXIT_READ_DR6       0x026
+#define        SVM_EXIT_READ_DR7       0x027
+#define        SVM_EXIT_WRITE_DR0      0x030
+#define        SVM_EXIT_WRITE_DR1      0x031
+#define        SVM_EXIT_WRITE_DR2      0x032
+#define        SVM_EXIT_WRITE_DR3      0x033
+#define        SVM_EXIT_WRITE_DR4      0x034
+#define        SVM_EXIT_WRITE_DR5      0x035
+#define        SVM_EXIT_WRITE_DR6      0x036
+#define        SVM_EXIT_WRITE_DR7      0x037
+#define SVM_EXIT_EXCP_BASE      0x040
+#define SVM_EXIT_INTR          0x060
+#define SVM_EXIT_NMI           0x061
+#define SVM_EXIT_SMI           0x062
+#define SVM_EXIT_INIT          0x063
+#define SVM_EXIT_VINTR         0x064
+#define SVM_EXIT_CR0_SEL_WRITE 0x065
+#define SVM_EXIT_IDTR_READ     0x066
+#define SVM_EXIT_GDTR_READ     0x067
+#define SVM_EXIT_LDTR_READ     0x068
+#define SVM_EXIT_TR_READ       0x069
+#define SVM_EXIT_IDTR_WRITE    0x06a
+#define SVM_EXIT_GDTR_WRITE    0x06b
+#define SVM_EXIT_LDTR_WRITE    0x06c
+#define SVM_EXIT_TR_WRITE      0x06d
+#define SVM_EXIT_RDTSC         0x06e
+#define SVM_EXIT_RDPMC         0x06f
+#define SVM_EXIT_PUSHF         0x070
+#define SVM_EXIT_POPF          0x071
+#define SVM_EXIT_CPUID         0x072
+#define SVM_EXIT_RSM           0x073
+#define SVM_EXIT_IRET          0x074
+#define SVM_EXIT_SWINT         0x075
+#define SVM_EXIT_INVD          0x076
+#define SVM_EXIT_PAUSE         0x077
+#define SVM_EXIT_HLT           0x078
+#define SVM_EXIT_INVLPG                0x079
+#define SVM_EXIT_INVLPGA       0x07a
+#define SVM_EXIT_IOIO          0x07b
+#define SVM_EXIT_MSR           0x07c
+#define SVM_EXIT_TASK_SWITCH   0x07d
+#define SVM_EXIT_FERR_FREEZE   0x07e
+#define SVM_EXIT_SHUTDOWN      0x07f
+#define SVM_EXIT_VMRUN         0x080
+#define SVM_EXIT_VMMCALL       0x081
+#define SVM_EXIT_VMLOAD                0x082
+#define SVM_EXIT_VMSAVE                0x083
+#define SVM_EXIT_STGI          0x084
+#define SVM_EXIT_CLGI          0x085
+#define SVM_EXIT_SKINIT                0x086
+#define SVM_EXIT_RDTSCP                0x087
+#define SVM_EXIT_ICEBP         0x088
+#define SVM_EXIT_WBINVD                0x089
+#define SVM_EXIT_NPF           0x400
+
+#define SVM_EXIT_ERR           -1
+
+#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) // TS and MP
+
+#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
+#define SVM_VMRUN  ".byte 0x0f, 0x01, 0xd8"
+#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
+#define SVM_CLGI   ".byte 0x0f, 0x01, 0xdd"
+#define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
+#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
+
+#endif
+
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
new file mode 100644 (file)
index 0000000..bda7a7a
--- /dev/null
@@ -0,0 +1,2002 @@
+/*
+ * Kernel-based Virtual Machine driver for Linux
+ *
+ * This module enables machines with Intel VT-x extensions to run virtual
+ * machines without emulation or binary translation.
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ *
+ * Authors:
+ *   Avi Kivity   <avi@qumranet.com>
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "kvm.h"
+#include "vmx.h"
+#include "kvm_vmx.h"
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/io.h>
+
+#include "segment_descriptor.h"
+
+#define MSR_IA32_FEATURE_CONTROL               0x03a
+
+MODULE_AUTHOR("Qumranet");
+MODULE_LICENSE("GPL");
+
+static DEFINE_PER_CPU(struct vmcs *, vmxarea);
+static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
+
+#ifdef __x86_64__
+#define HOST_IS_64 1
+#else
+#define HOST_IS_64 0
+#endif
+
+static struct vmcs_descriptor {
+       int size;
+       int order;
+       u32 revision_id;
+} vmcs_descriptor;
+
+#define VMX_SEGMENT_FIELD(seg)                                 \
+       [VCPU_SREG_##seg] = {                                   \
+               .selector = GUEST_##seg##_SELECTOR,             \
+               .base = GUEST_##seg##_BASE,                     \
+               .limit = GUEST_##seg##_LIMIT,                   \
+               .ar_bytes = GUEST_##seg##_AR_BYTES,             \
+       }
+
+static struct kvm_vmx_segment_field {
+       unsigned selector;
+       unsigned base;
+       unsigned limit;
+       unsigned ar_bytes;
+} kvm_vmx_segment_fields[] = {
+       VMX_SEGMENT_FIELD(CS),
+       VMX_SEGMENT_FIELD(DS),
+       VMX_SEGMENT_FIELD(ES),
+       VMX_SEGMENT_FIELD(FS),
+       VMX_SEGMENT_FIELD(GS),
+       VMX_SEGMENT_FIELD(SS),
+       VMX_SEGMENT_FIELD(TR),
+       VMX_SEGMENT_FIELD(LDTR),
+};
+
+static const u32 vmx_msr_index[] = {
+#ifdef __x86_64__
+       MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
+#endif
+       MSR_EFER, MSR_K6_STAR,
+};
+#define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index))
+
+struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr);
+
+static inline int is_page_fault(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+                            INTR_INFO_VALID_MASK)) ==
+               (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
+}
+
+static inline int is_external_interrupt(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+               == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
+static void vmcs_clear(struct vmcs *vmcs)
+{
+       u64 phys_addr = __pa(vmcs);
+       u8 error;
+
+       asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0"
+                     : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+                     : "cc", "memory");
+       if (error)
+               printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n",
+                      vmcs, phys_addr);
+}
+
+static void __vcpu_clear(void *arg)
+{
+       struct kvm_vcpu *vcpu = arg;
+       int cpu = smp_processor_id();
+
+       if (vcpu->cpu == cpu)
+               vmcs_clear(vcpu->vmcs);
+       if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
+               per_cpu(current_vmcs, cpu) = NULL;
+}
+
+static unsigned long vmcs_readl(unsigned long field)
+{
+       unsigned long value;
+
+       asm volatile (ASM_VMX_VMREAD_RDX_RAX
+                     : "=a"(value) : "d"(field) : "cc");
+       return value;
+}
+
+static u16 vmcs_read16(unsigned long field)
+{
+       return vmcs_readl(field);
+}
+
+static u32 vmcs_read32(unsigned long field)
+{
+       return vmcs_readl(field);
+}
+
+static u64 vmcs_read64(unsigned long field)
+{
+#ifdef __x86_64__
+       return vmcs_readl(field);
+#else
+       return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
+#endif
+}
+
+static void vmcs_writel(unsigned long field, unsigned long value)
+{
+       u8 error;
+
+       asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
+                      : "=q"(error) : "a"(value), "d"(field) : "cc" );
+       if (error)
+               printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
+                      field, value, vmcs_read32(VM_INSTRUCTION_ERROR));
+}
+
+static void vmcs_write16(unsigned long field, u16 value)
+{
+       vmcs_writel(field, value);
+}
+
+static void vmcs_write32(unsigned long field, u32 value)
+{
+       vmcs_writel(field, value);
+}
+
+static void vmcs_write64(unsigned long field, u64 value)
+{
+#ifdef __x86_64__
+       vmcs_writel(field, value);
+#else
+       vmcs_writel(field, value);
+       asm volatile ("");
+       vmcs_writel(field+1, value >> 32);
+#endif
+}
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
+static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
+{
+       u64 phys_addr = __pa(vcpu->vmcs);
+       int cpu;
+
+       cpu = get_cpu();
+
+       if (vcpu->cpu != cpu) {
+               smp_call_function(__vcpu_clear, vcpu, 0, 1);
+               vcpu->launched = 0;
+       }
+
+       if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+               u8 error;
+
+               per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+               asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
+                             : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
+                             : "cc");
+               if (error)
+                       printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
+                              vcpu->vmcs, phys_addr);
+       }
+
+       if (vcpu->cpu != cpu) {
+               struct descriptor_table dt;
+               unsigned long sysenter_esp;
+
+               vcpu->cpu = cpu;
+               /*
+                * Linux uses per-cpu TSS and GDT, so set these when switching
+                * processors.
+                */
+               vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */
+               get_gdt(&dt);
+               vmcs_writel(HOST_GDTR_BASE, dt.base);   /* 22.2.4 */
+
+               rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
+               vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+       }
+       return vcpu;
+}
+
+static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
+{
+       put_cpu();
+}
+
+static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
+{
+       return vmcs_readl(GUEST_RFLAGS);
+}
+
+static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+       vmcs_writel(GUEST_RFLAGS, rflags);
+}
+
+static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       unsigned long rip;
+       u32 interruptibility;
+
+       rip = vmcs_readl(GUEST_RIP);
+       rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+       vmcs_writel(GUEST_RIP, rip);
+
+       /*
+        * We emulated an instruction, so temporary interrupt blocking
+        * should be removed, if set.
+        */
+       interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
+       if (interruptibility & 3)
+               vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
+                            interruptibility & ~3);
+}
+
+static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
+{
+       printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n",
+              vmcs_readl(GUEST_RIP));
+       vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                    GP_VECTOR |
+                    INTR_TYPE_EXCEPTION |
+                    INTR_INFO_DELIEVER_CODE_MASK |
+                    INTR_INFO_VALID_MASK);
+}
+
+/*
+ * reads and returns guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset    -- 21.3
+ */
+static u64 guest_read_tsc(void)
+{
+       u64 host_tsc, tsc_offset;
+
+       rdtscll(host_tsc);
+       tsc_offset = vmcs_read64(TSC_OFFSET);
+       return host_tsc + tsc_offset;
+}
+
+/*
+ * writes 'guest_tsc' into guest's timestamp counter "register"
+ * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
+ */
+static void guest_write_tsc(u64 guest_tsc)
+{
+       u64 host_tsc;
+
+       rdtscll(host_tsc);
+       vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
+}
+
+static void reload_tss(void)
+{
+#ifndef __x86_64__
+
+       /*
+        * VT restores TR but not its size.  Useless.
+        */
+       struct descriptor_table gdt;
+       struct segment_descriptor *descs;
+
+       get_gdt(&gdt);
+       descs = (void *)gdt.base;
+       descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
+       load_TR_desc();
+#endif
+}
+
+/*
+ * Reads an msr value (of 'msr_index') into 'pdata'.
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+{
+       u64 data;
+       struct vmx_msr_entry *msr;
+
+       if (!pdata) {
+               printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
+               return -EINVAL;
+       }
+
+       switch (msr_index) {
+#ifdef __x86_64__
+       case MSR_FS_BASE:
+               data = vmcs_readl(GUEST_FS_BASE);
+               break;
+       case MSR_GS_BASE:
+               data = vmcs_readl(GUEST_GS_BASE);
+               break;
+       case MSR_EFER:
+               data = vcpu->shadow_efer;
+               break;
+#endif
+       case MSR_IA32_TIME_STAMP_COUNTER:
+               data = guest_read_tsc();
+               break;
+       case MSR_IA32_SYSENTER_CS:
+               data = vmcs_read32(GUEST_SYSENTER_CS);
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               data = vmcs_read32(GUEST_SYSENTER_EIP);
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               data = vmcs_read32(GUEST_SYSENTER_ESP);
+               break;
+       case MSR_IA32_MC0_CTL:
+       case MSR_IA32_MCG_STATUS:
+       case MSR_IA32_MCG_CAP:
+       case MSR_IA32_MC0_MISC:
+       case MSR_IA32_MC0_MISC+4:
+       case MSR_IA32_MC0_MISC+8:
+       case MSR_IA32_MC0_MISC+12:
+       case MSR_IA32_MC0_MISC+16:
+       case MSR_IA32_UCODE_REV:
+               /* MTRR registers */
+       case 0xfe:
+       case 0x200 ... 0x2ff:
+               data = 0;
+               break;
+       case MSR_IA32_APICBASE:
+               data = vcpu->apic_base;
+               break;
+       default:
+               msr = find_msr_entry(vcpu, msr_index);
+               if (!msr) {
+                       printk(KERN_ERR "kvm: unhandled rdmsr: %x\n", msr_index);
+                       return 1;
+               }
+               data = msr->data;
+               break;
+       }
+
+       *pdata = data;
+       return 0;
+}
+
+/*
+ * Writes msr value into into the appropriate "register".
+ * Returns 0 on success, non-0 otherwise.
+ * Assumes vcpu_load() was already called.
+ */
+static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+{
+       struct vmx_msr_entry *msr;
+       switch (msr_index) {
+#ifdef __x86_64__
+       case MSR_FS_BASE:
+               vmcs_writel(GUEST_FS_BASE, data);
+               break;
+       case MSR_GS_BASE:
+               vmcs_writel(GUEST_GS_BASE, data);
+               break;
+#endif
+       case MSR_IA32_SYSENTER_CS:
+               vmcs_write32(GUEST_SYSENTER_CS, data);
+               break;
+       case MSR_IA32_SYSENTER_EIP:
+               vmcs_write32(GUEST_SYSENTER_EIP, data);
+               break;
+       case MSR_IA32_SYSENTER_ESP:
+               vmcs_write32(GUEST_SYSENTER_ESP, data);
+               break;
+#ifdef __x86_64
+       case MSR_EFER:
+               set_efer(vcpu, data);
+               break;
+       case MSR_IA32_MC0_STATUS:
+               printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n"
+                           , __FUNCTION__, data);
+               break;
+#endif
+       case MSR_IA32_TIME_STAMP_COUNTER: {
+               guest_write_tsc(data);
+               break;
+       }
+       case MSR_IA32_UCODE_REV:
+       case MSR_IA32_UCODE_WRITE:
+       case 0x200 ... 0x2ff: /* MTRRs */
+               break;
+       case MSR_IA32_APICBASE:
+               vcpu->apic_base = data;
+               break;
+       default:
+               msr = find_msr_entry(vcpu, msr_index);
+               if (!msr) {
+                       printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr_index);
+                       return 1;
+               }
+               msr->data = data;
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Sync the rsp and rip registers into the vcpu structure.  This allows
+ * registers to be accessed by indexing vcpu->regs.
+ */
+static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu)
+{
+       vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
+       vcpu->rip = vmcs_readl(GUEST_RIP);
+}
+
+/*
+ * Syncs rsp and rip back into the vmcs.  Should be called after possible
+ * modification.
+ */
+static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
+{
+       vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]);
+       vmcs_writel(GUEST_RIP, vcpu->rip);
+}
+
+static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
+{
+       unsigned long dr7 = 0x400;
+       u32 exception_bitmap;
+       int old_singlestep;
+
+       exception_bitmap = vmcs_read32(EXCEPTION_BITMAP);
+       old_singlestep = vcpu->guest_debug.singlestep;
+
+       vcpu->guest_debug.enabled = dbg->enabled;
+       if (vcpu->guest_debug.enabled) {
+               int i;
+
+               dr7 |= 0x200;  /* exact */
+               for (i = 0; i < 4; ++i) {
+                       if (!dbg->breakpoints[i].enabled)
+                               continue;
+                       vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address;
+                       dr7 |= 2 << (i*2);    /* global enable */
+                       dr7 |= 0 << (i*4+16); /* execution breakpoint */
+               }
+
+               exception_bitmap |= (1u << 1);  /* Trap debug exceptions */
+
+               vcpu->guest_debug.singlestep = dbg->singlestep;
+       } else {
+               exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */
+               vcpu->guest_debug.singlestep = 0;
+       }
+
+       if (old_singlestep && !vcpu->guest_debug.singlestep) {
+               unsigned long flags;
+
+               flags = vmcs_readl(GUEST_RFLAGS);
+               flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+               vmcs_writel(GUEST_RFLAGS, flags);
+       }
+
+       vmcs_write32(EXCEPTION_BITMAP, exception_bitmap);
+       vmcs_writel(GUEST_DR7, dr7);
+
+       return 0;
+}
+
+static __init int cpu_has_kvm_support(void)
+{
+       unsigned long ecx = cpuid_ecx(1);
+       return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+}
+
+static __init int vmx_disabled_by_bios(void)
+{
+       u64 msr;
+
+       rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+       return (msr & 5) == 1; /* locked but not enabled */
+}
+
+static __init void hardware_enable(void *garbage)
+{
+       int cpu = raw_smp_processor_id();
+       u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
+       u64 old;
+
+       rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
+       if ((old & 5) == 0)
+               /* enable and lock */
+               wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
+       write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+       asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
+                     : "memory", "cc");
+}
+
+static void hardware_disable(void *garbage)
+{
+       asm volatile (ASM_VMX_VMXOFF : : : "cc");
+}
+
+static __init void setup_vmcs_descriptor(void)
+{
+       u32 vmx_msr_low, vmx_msr_high;
+
+       rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
+       vmcs_descriptor.size = vmx_msr_high & 0x1fff;
+       vmcs_descriptor.order = get_order(vmcs_descriptor.size);
+       vmcs_descriptor.revision_id = vmx_msr_low;
+};
+
+static struct vmcs *alloc_vmcs_cpu(int cpu)
+{
+       int node = cpu_to_node(cpu);
+       struct page *pages;
+       struct vmcs *vmcs;
+
+       pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order);
+       if (!pages)
+               return NULL;
+       vmcs = page_address(pages);
+       memset(vmcs, 0, vmcs_descriptor.size);
+       vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */
+       return vmcs;
+}
+
+static struct vmcs *alloc_vmcs(void)
+{
+       return alloc_vmcs_cpu(smp_processor_id());
+}
+
+static void free_vmcs(struct vmcs *vmcs)
+{
+       free_pages((unsigned long)vmcs, vmcs_descriptor.order);
+}
+
+static __exit void free_kvm_area(void)
+{
+       int cpu;
+
+       for_each_online_cpu(cpu)
+               free_vmcs(per_cpu(vmxarea, cpu));
+}
+
+extern struct vmcs *alloc_vmcs_cpu(int cpu);
+
+static __init int alloc_kvm_area(void)
+{
+       int cpu;
+
+       for_each_online_cpu(cpu) {
+               struct vmcs *vmcs;
+
+               vmcs = alloc_vmcs_cpu(cpu);
+               if (!vmcs) {
+                       free_kvm_area();
+                       return -ENOMEM;
+               }
+
+               per_cpu(vmxarea, cpu) = vmcs;
+       }
+       return 0;
+}
+
+static __init int hardware_setup(void)
+{
+       setup_vmcs_descriptor();
+       return alloc_kvm_area();
+}
+
+static __exit void hardware_unsetup(void)
+{
+       free_kvm_area();
+}
+
+static void update_exception_bitmap(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->rmode.active)
+               vmcs_write32(EXCEPTION_BITMAP, ~0);
+       else
+               vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
+}
+
+static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+       if (vmcs_readl(sf->base) == save->base) {
+               vmcs_write16(sf->selector, save->selector);
+               vmcs_writel(sf->base, save->base);
+               vmcs_write32(sf->limit, save->limit);
+               vmcs_write32(sf->ar_bytes, save->ar);
+       } else {
+               u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK)
+                       << AR_DPL_SHIFT;
+               vmcs_write32(sf->ar_bytes, 0x93 | dpl);
+       }
+}
+
+static void enter_pmode(struct kvm_vcpu *vcpu)
+{
+       unsigned long flags;
+
+       vcpu->rmode.active = 0;
+
+       vmcs_writel(GUEST_TR_BASE, vcpu->rmode.tr.base);
+       vmcs_write32(GUEST_TR_LIMIT, vcpu->rmode.tr.limit);
+       vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar);
+
+       flags = vmcs_readl(GUEST_RFLAGS);
+       flags &= ~(IOPL_MASK | X86_EFLAGS_VM);
+       flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
+       vmcs_writel(GUEST_RFLAGS, flags);
+
+       vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) |
+                       (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK));
+
+       update_exception_bitmap(vcpu);
+
+       fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->rmode.es);
+       fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->rmode.ds);
+       fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->rmode.gs);
+       fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->rmode.fs);
+
+       vmcs_write16(GUEST_SS_SELECTOR, 0);
+       vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
+
+       vmcs_write16(GUEST_CS_SELECTOR,
+                    vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK);
+       vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+}
+
+static int rmode_tss_base(struct kvm* kvm)
+{
+       gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
+       return base_gfn << PAGE_SHIFT;
+}
+
+static void fix_rmode_seg(int seg, struct kvm_save_segment *save)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+       save->selector = vmcs_read16(sf->selector);
+       save->base = vmcs_readl(sf->base);
+       save->limit = vmcs_read32(sf->limit);
+       save->ar = vmcs_read32(sf->ar_bytes);
+       vmcs_write16(sf->selector, vmcs_readl(sf->base) >> 4);
+       vmcs_write32(sf->limit, 0xffff);
+       vmcs_write32(sf->ar_bytes, 0xf3);
+}
+
+static void enter_rmode(struct kvm_vcpu *vcpu)
+{
+       unsigned long flags;
+
+       vcpu->rmode.active = 1;
+
+       vcpu->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
+       vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
+
+       vcpu->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT);
+       vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1);
+
+       vcpu->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES);
+       vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
+
+       flags = vmcs_readl(GUEST_RFLAGS);
+       vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT;
+
+       flags |= IOPL_MASK | X86_EFLAGS_VM;
+
+       vmcs_writel(GUEST_RFLAGS, flags);
+       vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK);
+       update_exception_bitmap(vcpu);
+
+       vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
+       vmcs_write32(GUEST_SS_LIMIT, 0xffff);
+       vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
+
+       vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
+       vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
+
+       fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
+       fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds);
+       fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
+       fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
+}
+
+#ifdef __x86_64__
+
+static void enter_lmode(struct kvm_vcpu *vcpu)
+{
+       u32 guest_tr_ar;
+
+       guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
+       if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
+               printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
+                      __FUNCTION__);
+               vmcs_write32(GUEST_TR_AR_BYTES,
+                            (guest_tr_ar & ~AR_TYPE_MASK)
+                            | AR_TYPE_BUSY_64_TSS);
+       }
+
+       vcpu->shadow_efer |= EFER_LMA;
+
+       find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME;
+       vmcs_write32(VM_ENTRY_CONTROLS,
+                    vmcs_read32(VM_ENTRY_CONTROLS)
+                    | VM_ENTRY_CONTROLS_IA32E_MASK);
+}
+
+static void exit_lmode(struct kvm_vcpu *vcpu)
+{
+       vcpu->shadow_efer &= ~EFER_LMA;
+
+       vmcs_write32(VM_ENTRY_CONTROLS,
+                    vmcs_read32(VM_ENTRY_CONTROLS)
+                    & ~VM_ENTRY_CONTROLS_IA32E_MASK);
+}
+
+#endif
+
+static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+       if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
+               enter_pmode(vcpu);
+
+       if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+               enter_rmode(vcpu);
+
+#ifdef __x86_64__
+       if (vcpu->shadow_efer & EFER_LME) {
+               if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
+                       enter_lmode(vcpu);
+               if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
+                       exit_lmode(vcpu);
+       }
+#endif
+
+       vmcs_writel(CR0_READ_SHADOW, cr0);
+       vmcs_writel(GUEST_CR0,
+                   (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+       vcpu->cr0 = cr0;
+}
+
+/*
+ * Used when restoring the VM to avoid corrupting segment registers
+ */
+static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
+{
+       vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
+       update_exception_bitmap(vcpu);
+       vmcs_writel(CR0_READ_SHADOW, cr0);
+       vmcs_writel(GUEST_CR0,
+                   (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
+       vcpu->cr0 = cr0;
+}
+
+static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+       vmcs_writel(GUEST_CR3, cr3);
+}
+
+static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
+{
+       vmcs_writel(CR4_READ_SHADOW, cr4);
+       vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
+                   KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
+       vcpu->cr4 = cr4;
+}
+
+#ifdef __x86_64__
+
+static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
+{
+       struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+
+       vcpu->shadow_efer = efer;
+       if (efer & EFER_LMA) {
+               vmcs_write32(VM_ENTRY_CONTROLS,
+                                    vmcs_read32(VM_ENTRY_CONTROLS) |
+                                    VM_ENTRY_CONTROLS_IA32E_MASK);
+               msr->data = efer;
+
+       } else {
+               vmcs_write32(VM_ENTRY_CONTROLS,
+                                    vmcs_read32(VM_ENTRY_CONTROLS) &
+                                    ~VM_ENTRY_CONTROLS_IA32E_MASK);
+
+               msr->data = efer & ~EFER_LME;
+       }
+}
+
+#endif
+
+static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+       return vmcs_readl(sf->base);
+}
+
+static void vmx_get_segment(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+       u32 ar;
+
+       var->base = vmcs_readl(sf->base);
+       var->limit = vmcs_read32(sf->limit);
+       var->selector = vmcs_read16(sf->selector);
+       ar = vmcs_read32(sf->ar_bytes);
+       if (ar & AR_UNUSABLE_MASK)
+               ar = 0;
+       var->type = ar & 15;
+       var->s = (ar >> 4) & 1;
+       var->dpl = (ar >> 5) & 3;
+       var->present = (ar >> 7) & 1;
+       var->avl = (ar >> 12) & 1;
+       var->l = (ar >> 13) & 1;
+       var->db = (ar >> 14) & 1;
+       var->g = (ar >> 15) & 1;
+       var->unusable = (ar >> 16) & 1;
+}
+
+static void vmx_set_segment(struct kvm_vcpu *vcpu,
+                           struct kvm_segment *var, int seg)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+       u32 ar;
+
+       vmcs_writel(sf->base, var->base);
+       vmcs_write32(sf->limit, var->limit);
+       vmcs_write16(sf->selector, var->selector);
+       if (var->unusable)
+               ar = 1 << 16;
+       else {
+               ar = var->type & 15;
+               ar |= (var->s & 1) << 4;
+               ar |= (var->dpl & 3) << 5;
+               ar |= (var->present & 1) << 7;
+               ar |= (var->avl & 1) << 12;
+               ar |= (var->l & 1) << 13;
+               ar |= (var->db & 1) << 14;
+               ar |= (var->g & 1) << 15;
+       }
+       vmcs_write32(sf->ar_bytes, ar);
+}
+
+static int vmx_is_long_mode(struct kvm_vcpu *vcpu)
+{
+       return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
+}
+
+static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+       u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
+
+       *db = (ar >> 14) & 1;
+       *l = (ar >> 13) & 1;
+}
+
+static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
+       dt->base = vmcs_readl(GUEST_IDTR_BASE);
+}
+
+static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       vmcs_write32(GUEST_IDTR_LIMIT, dt->limit);
+       vmcs_writel(GUEST_IDTR_BASE, dt->base);
+}
+
+static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       dt->limit = vmcs_read32(GUEST_GDTR_LIMIT);
+       dt->base = vmcs_readl(GUEST_GDTR_BASE);
+}
+
+static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
+{
+       vmcs_write32(GUEST_GDTR_LIMIT, dt->limit);
+       vmcs_writel(GUEST_GDTR_BASE, dt->base);
+}
+
+static int init_rmode_tss(struct kvm* kvm)
+{
+       struct page *p1, *p2, *p3;
+       gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
+       char *page;
+
+       p1 = _gfn_to_page(kvm, fn++);
+       p2 = _gfn_to_page(kvm, fn++);
+       p3 = _gfn_to_page(kvm, fn);
+
+       if (!p1 || !p2 || !p3) {
+               kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
+               return 0;
+       }
+
+       page = kmap_atomic(p1, KM_USER0);
+       memset(page, 0, PAGE_SIZE);
+       *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
+       kunmap_atomic(page, KM_USER0);
+
+       page = kmap_atomic(p2, KM_USER0);
+       memset(page, 0, PAGE_SIZE);
+       kunmap_atomic(page, KM_USER0);
+
+       page = kmap_atomic(p3, KM_USER0);
+       memset(page, 0, PAGE_SIZE);
+       *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
+       kunmap_atomic(page, KM_USER0);
+
+       return 1;
+}
+
+static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val)
+{
+       u32 msr_high, msr_low;
+
+       rdmsr(msr, msr_low, msr_high);
+
+       val &= msr_high;
+       val |= msr_low;
+       vmcs_write32(vmcs_field, val);
+}
+
+static void seg_setup(int seg)
+{
+       struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+
+       vmcs_write16(sf->selector, 0);
+       vmcs_writel(sf->base, 0);
+       vmcs_write32(sf->limit, 0xffff);
+       vmcs_write32(sf->ar_bytes, 0x93);
+}
+
+/*
+ * Sets up the vmcs for emulated real mode.
+ */
+static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+       u32 host_sysenter_cs;
+       u32 junk;
+       unsigned long a;
+       struct descriptor_table dt;
+       int i;
+       int ret = 0;
+       int nr_good_msrs;
+       extern asmlinkage void kvm_vmx_return(void);
+
+       if (!init_rmode_tss(vcpu->kvm)) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memset(vcpu->regs, 0, sizeof(vcpu->regs));
+       vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
+       vcpu->cr8 = 0;
+       vcpu->apic_base = 0xfee00000 |
+                       /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
+                       MSR_IA32_APICBASE_ENABLE;
+
+       fx_init(vcpu);
+
+       /*
+        * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
+        * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4.  Sigh.
+        */
+       vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+       vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+       vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+       vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+
+       seg_setup(VCPU_SREG_DS);
+       seg_setup(VCPU_SREG_ES);
+       seg_setup(VCPU_SREG_FS);
+       seg_setup(VCPU_SREG_GS);
+       seg_setup(VCPU_SREG_SS);
+
+       vmcs_write16(GUEST_TR_SELECTOR, 0);
+       vmcs_writel(GUEST_TR_BASE, 0);
+       vmcs_write32(GUEST_TR_LIMIT, 0xffff);
+       vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
+
+       vmcs_write16(GUEST_LDTR_SELECTOR, 0);
+       vmcs_writel(GUEST_LDTR_BASE, 0);
+       vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
+       vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
+
+       vmcs_write32(GUEST_SYSENTER_CS, 0);
+       vmcs_writel(GUEST_SYSENTER_ESP, 0);
+       vmcs_writel(GUEST_SYSENTER_EIP, 0);
+
+       vmcs_writel(GUEST_RFLAGS, 0x02);
+       vmcs_writel(GUEST_RIP, 0xfff0);
+       vmcs_writel(GUEST_RSP, 0);
+
+       vmcs_writel(GUEST_CR3, 0);
+
+       //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
+       vmcs_writel(GUEST_DR7, 0x400);
+
+       vmcs_writel(GUEST_GDTR_BASE, 0);
+       vmcs_write32(GUEST_GDTR_LIMIT, 0xffff);
+
+       vmcs_writel(GUEST_IDTR_BASE, 0);
+       vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
+
+       vmcs_write32(GUEST_ACTIVITY_STATE, 0);
+       vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
+       vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+
+       /* I/O */
+       vmcs_write64(IO_BITMAP_A, 0);
+       vmcs_write64(IO_BITMAP_B, 0);
+
+       guest_write_tsc(0);
+
+       vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
+
+       /* Special registers */
+       vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
+
+       /* Control */
+       vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS_MSR,
+                              PIN_BASED_VM_EXEC_CONTROL,
+                              PIN_BASED_EXT_INTR_MASK   /* 20.6.1 */
+                              | PIN_BASED_NMI_EXITING   /* 20.6.1 */
+                       );
+       vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS_MSR,
+                              CPU_BASED_VM_EXEC_CONTROL,
+                              CPU_BASED_HLT_EXITING         /* 20.6.2 */
+                              | CPU_BASED_CR8_LOAD_EXITING    /* 20.6.2 */
+                              | CPU_BASED_CR8_STORE_EXITING   /* 20.6.2 */
+                              | CPU_BASED_UNCOND_IO_EXITING   /* 20.6.2 */
+                              | CPU_BASED_INVDPG_EXITING
+                              | CPU_BASED_MOV_DR_EXITING
+                              | CPU_BASED_USE_TSC_OFFSETING   /* 21.3 */
+                       );
+
+       vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
+       vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
+       vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+       vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
+
+       vmcs_writel(HOST_CR0, read_cr0());  /* 22.2.3 */
+       vmcs_writel(HOST_CR4, read_cr4());  /* 22.2.3, 22.2.5 */
+       vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
+
+       vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS);  /* 22.2.4 */
+       vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
+       vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
+       vmcs_write16(HOST_FS_SELECTOR, read_fs());    /* 22.2.4 */
+       vmcs_write16(HOST_GS_SELECTOR, read_gs());    /* 22.2.4 */
+       vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
+#ifdef __x86_64__
+       rdmsrl(MSR_FS_BASE, a);
+       vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */
+       rdmsrl(MSR_GS_BASE, a);
+       vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */
+#else
+       vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */
+       vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */
+#endif
+
+       vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
+
+       get_idt(&dt);
+       vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
+
+
+       vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); /* 22.2.5 */
+
+       rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
+       vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
+       rdmsrl(MSR_IA32_SYSENTER_ESP, a);
+       vmcs_writel(HOST_IA32_SYSENTER_ESP, a);   /* 22.2.3 */
+       rdmsrl(MSR_IA32_SYSENTER_EIP, a);
+       vmcs_writel(HOST_IA32_SYSENTER_EIP, a);   /* 22.2.3 */
+
+       ret = -ENOMEM;
+       vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vcpu->guest_msrs)
+               goto out;
+       vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vcpu->host_msrs)
+               goto out_free_guest_msrs;
+
+       for (i = 0; i < NR_VMX_MSR; ++i) {
+               u32 index = vmx_msr_index[i];
+               u32 data_low, data_high;
+               u64 data;
+               int j = vcpu->nmsrs;
+
+               if (rdmsr_safe(index, &data_low, &data_high) < 0)
+                       continue;
+               data = data_low | ((u64)data_high << 32);
+               vcpu->host_msrs[j].index = index;
+               vcpu->host_msrs[j].reserved = 0;
+               vcpu->host_msrs[j].data = data;
+               vcpu->guest_msrs[j] = vcpu->host_msrs[j];
+               ++vcpu->nmsrs;
+       }
+       printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs);
+
+       nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS;
+       vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
+                   virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
+       vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
+                   virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
+       vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
+                   virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS));
+       vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CONTROLS,
+                              (HOST_IS_64 << 9));  /* 22.2,1, 20.7.1 */
+       vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
+       vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs);  /* 22.2.2 */
+       vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+
+
+       /* 22.2.1, 20.8.1 */
+       vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS_MSR,
+                               VM_ENTRY_CONTROLS, 0);
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);  /* 22.2.1 */
+
+       vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
+       vmcs_writel(TPR_THRESHOLD, 0);
+
+       vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK);
+       vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
+
+       vcpu->cr0 = 0x60000010;
+       vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
+       vmx_set_cr4(vcpu, 0);
+#ifdef __x86_64__
+       vmx_set_efer(vcpu, 0);
+#endif
+
+       return 0;
+
+out_free_guest_msrs:
+       kfree(vcpu->guest_msrs);
+out:
+       return ret;
+}
+
+static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       u16 ent[2];
+       u16 cs;
+       u16 ip;
+       unsigned long flags;
+       unsigned long ss_base = vmcs_readl(GUEST_SS_BASE);
+       u16 sp =  vmcs_readl(GUEST_RSP);
+       u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
+
+       if (sp > ss_limit || sp - 6 > sp) {
+               vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
+                           __FUNCTION__,
+                           vmcs_readl(GUEST_RSP),
+                           vmcs_readl(GUEST_SS_BASE),
+                           vmcs_read32(GUEST_SS_LIMIT));
+               return;
+       }
+
+       if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) !=
+                                                               sizeof(ent)) {
+               vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
+               return;
+       }
+
+       flags =  vmcs_readl(GUEST_RFLAGS);
+       cs =  vmcs_readl(GUEST_CS_BASE) >> 4;
+       ip =  vmcs_readl(GUEST_RIP);
+
+
+       if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 ||
+           kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 ||
+           kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) {
+               vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
+               return;
+       }
+
+       vmcs_writel(GUEST_RFLAGS, flags &
+                   ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF));
+       vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ;
+       vmcs_writel(GUEST_CS_BASE, ent[1] << 4);
+       vmcs_writel(GUEST_RIP, ent[0]);
+       vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
+}
+
+static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+{
+       int word_index = __ffs(vcpu->irq_summary);
+       int bit_index = __ffs(vcpu->irq_pending[word_index]);
+       int irq = word_index * BITS_PER_LONG + bit_index;
+
+       clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+       if (!vcpu->irq_pending[word_index])
+               clear_bit(word_index, &vcpu->irq_summary);
+
+       if (vcpu->rmode.active) {
+               inject_rmode_irq(vcpu, irq);
+               return;
+       }
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
+static void kvm_try_inject_irq(struct kvm_vcpu *vcpu)
+{
+       if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)
+           && (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0)
+               /*
+                * Interrupts enabled, and not blocked by sti or mov ss. Good.
+                */
+               kvm_do_inject_irq(vcpu);
+       else
+               /*
+                * Interrupts blocked.  Wait for unblock.
+                */
+               vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
+                            vmcs_read32(CPU_BASED_VM_EXEC_CONTROL)
+                            | CPU_BASED_VIRTUAL_INTR_PENDING);
+}
+
+static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
+{
+       struct kvm_guest_debug *dbg = &vcpu->guest_debug;
+
+       set_debugreg(dbg->bp[0], 0);
+       set_debugreg(dbg->bp[1], 1);
+       set_debugreg(dbg->bp[2], 2);
+       set_debugreg(dbg->bp[3], 3);
+
+       if (dbg->singlestep) {
+               unsigned long flags;
+
+               flags = vmcs_readl(GUEST_RFLAGS);
+               flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+               vmcs_writel(GUEST_RFLAGS, flags);
+       }
+}
+
+static int handle_rmode_exception(struct kvm_vcpu *vcpu,
+                                 int vec, u32 err_code)
+{
+       if (!vcpu->rmode.active)
+               return 0;
+
+       if (vec == GP_VECTOR && err_code == 0)
+               if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
+                       return 1;
+       return 0;
+}
+
+static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 intr_info, error_code;
+       unsigned long cr2, rip;
+       u32 vect_info;
+       enum emulation_result er;
+
+       vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+       if ((vect_info & VECTORING_INFO_VALID_MASK) &&
+                                               !is_page_fault(intr_info)) {
+               printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
+                      "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
+       }
+
+       if (is_external_interrupt(vect_info)) {
+               int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
+               set_bit(irq, vcpu->irq_pending);
+               set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+       }
+
+       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
+               asm ("int $2");
+               return 1;
+       }
+       error_code = 0;
+       rip = vmcs_readl(GUEST_RIP);
+       if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
+               error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
+       if (is_page_fault(intr_info)) {
+               cr2 = vmcs_readl(EXIT_QUALIFICATION);
+
+               spin_lock(&vcpu->kvm->lock);
+               if (!vcpu->mmu.page_fault(vcpu, cr2, error_code)) {
+                       spin_unlock(&vcpu->kvm->lock);
+                       return 1;
+               }
+
+               er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
+               spin_unlock(&vcpu->kvm->lock);
+
+               switch (er) {
+               case EMULATE_DONE:
+                       return 1;
+               case EMULATE_DO_MMIO:
+                       ++kvm_stat.mmio_exits;
+                       kvm_run->exit_reason = KVM_EXIT_MMIO;
+                       return 0;
+                case EMULATE_FAIL:
+                       vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       if (vcpu->rmode.active &&
+           handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
+                                                               error_code))
+               return 1;
+
+       if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
+               kvm_run->exit_reason = KVM_EXIT_DEBUG;
+               return 0;
+       }
+       kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
+       kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK;
+       kvm_run->ex.error_code = error_code;
+       return 0;
+}
+
+static int handle_external_interrupt(struct kvm_vcpu *vcpu,
+                                    struct kvm_run *kvm_run)
+{
+       ++kvm_stat.irq_exits;
+       return 1;
+}
+
+
+static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
+{
+       u64 inst;
+       gva_t rip;
+       int countr_size;
+       int i, n;
+
+       if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) {
+               countr_size = 2;
+       } else {
+               u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
+
+               countr_size = (cs_ar & AR_L_MASK) ? 8:
+                             (cs_ar & AR_DB_MASK) ? 4: 2;
+       }
+
+       rip =  vmcs_readl(GUEST_RIP);
+       if (countr_size != 8)
+               rip += vmcs_readl(GUEST_CS_BASE);
+
+       n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst);
+
+       for (i = 0; i < n; i++) {
+               switch (((u8*)&inst)[i]) {
+               case 0xf0:
+               case 0xf2:
+               case 0xf3:
+               case 0x2e:
+               case 0x36:
+               case 0x3e:
+               case 0x26:
+               case 0x64:
+               case 0x65:
+               case 0x66:
+                       break;
+               case 0x67:
+                       countr_size = (countr_size == 2) ? 4: (countr_size >> 1);
+               default:
+                       goto done;
+               }
+       }
+       return 0;
+done:
+       countr_size *= 8;
+       *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
+       return 1;
+}
+
+static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u64 exit_qualification;
+
+       ++kvm_stat.io_exits;
+       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       kvm_run->exit_reason = KVM_EXIT_IO;
+       if (exit_qualification & 8)
+               kvm_run->io.direction = KVM_EXIT_IO_IN;
+       else
+               kvm_run->io.direction = KVM_EXIT_IO_OUT;
+       kvm_run->io.size = (exit_qualification & 7) + 1;
+       kvm_run->io.string = (exit_qualification & 16) != 0;
+       kvm_run->io.string_down
+               = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
+       kvm_run->io.rep = (exit_qualification & 32) != 0;
+       kvm_run->io.port = exit_qualification >> 16;
+       if (kvm_run->io.string) {
+               if (!get_io_count(vcpu, &kvm_run->io.count))
+                       return 1;
+               kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+       } else
+               kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */
+       return 0;
+}
+
+static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u64 address = vmcs_read64(EXIT_QUALIFICATION);
+       int instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+       spin_lock(&vcpu->kvm->lock);
+       vcpu->mmu.inval_page(vcpu, address);
+       spin_unlock(&vcpu->kvm->lock);
+       vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP) + instruction_length);
+       return 1;
+}
+
+static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u64 exit_qualification;
+       int cr;
+       int reg;
+
+       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       cr = exit_qualification & 15;
+       reg = (exit_qualification >> 8) & 15;
+       switch ((exit_qualification >> 4) & 3) {
+       case 0: /* mov to cr */
+               switch (cr) {
+               case 0:
+                       vcpu_load_rsp_rip(vcpu);
+                       set_cr0(vcpu, vcpu->regs[reg]);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               case 3:
+                       vcpu_load_rsp_rip(vcpu);
+                       set_cr3(vcpu, vcpu->regs[reg]);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               case 4:
+                       vcpu_load_rsp_rip(vcpu);
+                       set_cr4(vcpu, vcpu->regs[reg]);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               case 8:
+                       vcpu_load_rsp_rip(vcpu);
+                       set_cr8(vcpu, vcpu->regs[reg]);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               };
+               break;
+       case 1: /*mov from cr*/
+               switch (cr) {
+               case 3:
+                       vcpu_load_rsp_rip(vcpu);
+                       vcpu->regs[reg] = vcpu->cr3;
+                       vcpu_put_rsp_rip(vcpu);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               case 8:
+                       printk(KERN_DEBUG "handle_cr: read CR8 "
+                              "cpu erratum AA15\n");
+                       vcpu_load_rsp_rip(vcpu);
+                       vcpu->regs[reg] = vcpu->cr8;
+                       vcpu_put_rsp_rip(vcpu);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+               break;
+       case 3: /* lmsw */
+               lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f);
+
+               skip_emulated_instruction(vcpu);
+               return 1;
+       default:
+               break;
+       }
+       kvm_run->exit_reason = 0;
+       printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n",
+              (int)(exit_qualification >> 4) & 3, cr);
+       return 0;
+}
+
+static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u64 exit_qualification;
+       unsigned long val;
+       int dr, reg;
+
+       /*
+        * FIXME: this code assumes the host is debugging the guest.
+        *        need to deal with guest debugging itself too.
+        */
+       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       dr = exit_qualification & 7;
+       reg = (exit_qualification >> 8) & 15;
+       vcpu_load_rsp_rip(vcpu);
+       if (exit_qualification & 16) {
+               /* mov from dr */
+               switch (dr) {
+               case 6:
+                       val = 0xffff0ff0;
+                       break;
+               case 7:
+                       val = 0x400;
+                       break;
+               default:
+                       val = 0;
+               }
+               vcpu->regs[reg] = val;
+       } else {
+               /* mov to dr */
+       }
+       vcpu_put_rsp_rip(vcpu);
+       skip_emulated_instruction(vcpu);
+       return 1;
+}
+
+static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       kvm_run->exit_reason = KVM_EXIT_CPUID;
+       return 0;
+}
+
+static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+       u64 data;
+
+       if (vmx_get_msr(vcpu, ecx, &data)) {
+               vmx_inject_gp(vcpu, 0);
+               return 1;
+       }
+
+       /* FIXME: handling of bits 32:63 of rax, rdx */
+       vcpu->regs[VCPU_REGS_RAX] = data & -1u;
+       vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u;
+       skip_emulated_instruction(vcpu);
+       return 1;
+}
+
+static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+       u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u)
+               | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
+
+       if (vmx_set_msr(vcpu, ecx, data) != 0) {
+               vmx_inject_gp(vcpu, 0);
+               return 1;
+       }
+
+       skip_emulated_instruction(vcpu);
+       return 1;
+}
+
+static int handle_interrupt_window(struct kvm_vcpu *vcpu,
+                                  struct kvm_run *kvm_run)
+{
+       /* Turn off interrupt window reporting. */
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
+                    vmcs_read32(CPU_BASED_VM_EXEC_CONTROL)
+                    & ~CPU_BASED_VIRTUAL_INTR_PENDING);
+       return 1;
+}
+
+static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       skip_emulated_instruction(vcpu);
+       if (vcpu->irq_summary && (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF))
+               return 1;
+
+       kvm_run->exit_reason = KVM_EXIT_HLT;
+       return 0;
+}
+
+/*
+ * The exit handlers return 1 if the exit was handled fully and guest execution
+ * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
+ * to be done to userspace and return 0.
+ */
+static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
+                                     struct kvm_run *kvm_run) = {
+       [EXIT_REASON_EXCEPTION_NMI]           = handle_exception,
+       [EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt,
+       [EXIT_REASON_IO_INSTRUCTION]          = handle_io,
+       [EXIT_REASON_INVLPG]                  = handle_invlpg,
+       [EXIT_REASON_CR_ACCESS]               = handle_cr,
+       [EXIT_REASON_DR_ACCESS]               = handle_dr,
+       [EXIT_REASON_CPUID]                   = handle_cpuid,
+       [EXIT_REASON_MSR_READ]                = handle_rdmsr,
+       [EXIT_REASON_MSR_WRITE]               = handle_wrmsr,
+       [EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
+       [EXIT_REASON_HLT]                     = handle_halt,
+};
+
+static const int kvm_vmx_max_exit_handlers =
+       sizeof(kvm_vmx_exit_handlers) / sizeof(*kvm_vmx_exit_handlers);
+
+/*
+ * The guest has exited.  See if we can fix it or if we need userspace
+ * assistance.
+ */
+static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+{
+       u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+
+       if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
+                               exit_reason != EXIT_REASON_EXCEPTION_NMI )
+               printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
+                      "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
+       kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+       if (exit_reason < kvm_vmx_max_exit_handlers
+           && kvm_vmx_exit_handlers[exit_reason])
+               return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
+       else {
+               kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+               kvm_run->hw.hardware_exit_reason = exit_reason;
+       }
+       return 0;
+}
+
+static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u8 fail;
+       u16 fs_sel, gs_sel, ldt_sel;
+       int fs_gs_ldt_reload_needed;
+
+again:
+       /*
+        * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
+        * allow segment selectors with cpl > 0 or ti == 1.
+        */
+       fs_sel = read_fs();
+       gs_sel = read_gs();
+       ldt_sel = read_ldt();
+       fs_gs_ldt_reload_needed = (fs_sel & 7) | (gs_sel & 7) | ldt_sel;
+       if (!fs_gs_ldt_reload_needed) {
+               vmcs_write16(HOST_FS_SELECTOR, fs_sel);
+               vmcs_write16(HOST_GS_SELECTOR, gs_sel);
+       } else {
+               vmcs_write16(HOST_FS_SELECTOR, 0);
+               vmcs_write16(HOST_GS_SELECTOR, 0);
+       }
+
+#ifdef __x86_64__
+       vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
+       vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
+#else
+       vmcs_writel(HOST_FS_BASE, segment_base(fs_sel));
+       vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
+#endif
+
+       if (vcpu->irq_summary &&
+           !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
+               kvm_try_inject_irq(vcpu);
+
+       if (vcpu->guest_debug.enabled)
+               kvm_guest_debug_pre(vcpu);
+
+       fx_save(vcpu->host_fx_image);
+       fx_restore(vcpu->guest_fx_image);
+
+       save_msrs(vcpu->host_msrs, vcpu->nmsrs);
+       load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+
+       asm (
+               /* Store host registers */
+               "pushf \n\t"
+#ifdef __x86_64__
+               "push %%rax; push %%rbx; push %%rdx;"
+               "push %%rsi; push %%rdi; push %%rbp;"
+               "push %%r8;  push %%r9;  push %%r10; push %%r11;"
+               "push %%r12; push %%r13; push %%r14; push %%r15;"
+               "push %%rcx \n\t"
+               ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+#else
+               "pusha; push %%ecx \n\t"
+               ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+#endif
+               /* Check if vmlaunch of vmresume is needed */
+               "cmp $0, %1 \n\t"
+               /* Load guest registers.  Don't clobber flags. */
+#ifdef __x86_64__
+               "mov %c[cr2](%3), %%rax \n\t"
+               "mov %%rax, %%cr2 \n\t"
+               "mov %c[rax](%3), %%rax \n\t"
+               "mov %c[rbx](%3), %%rbx \n\t"
+               "mov %c[rdx](%3), %%rdx \n\t"
+               "mov %c[rsi](%3), %%rsi \n\t"
+               "mov %c[rdi](%3), %%rdi \n\t"
+               "mov %c[rbp](%3), %%rbp \n\t"
+               "mov %c[r8](%3),  %%r8  \n\t"
+               "mov %c[r9](%3),  %%r9  \n\t"
+               "mov %c[r10](%3), %%r10 \n\t"
+               "mov %c[r11](%3), %%r11 \n\t"
+               "mov %c[r12](%3), %%r12 \n\t"
+               "mov %c[r13](%3), %%r13 \n\t"
+               "mov %c[r14](%3), %%r14 \n\t"
+               "mov %c[r15](%3), %%r15 \n\t"
+               "mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */
+#else
+               "mov %c[cr2](%3), %%eax \n\t"
+               "mov %%eax,   %%cr2 \n\t"
+               "mov %c[rax](%3), %%eax \n\t"
+               "mov %c[rbx](%3), %%ebx \n\t"
+               "mov %c[rdx](%3), %%edx \n\t"
+               "mov %c[rsi](%3), %%esi \n\t"
+               "mov %c[rdi](%3), %%edi \n\t"
+               "mov %c[rbp](%3), %%ebp \n\t"
+               "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
+#endif
+               /* Enter guest mode */
+               "jne launched \n\t"
+               ASM_VMX_VMLAUNCH "\n\t"
+               "jmp kvm_vmx_return \n\t"
+               "launched: " ASM_VMX_VMRESUME "\n\t"
+               ".globl kvm_vmx_return \n\t"
+               "kvm_vmx_return: "
+               /* Save guest registers, load host registers, keep flags */
+#ifdef __x86_64__
+               "xchg %3,     0(%%rsp) \n\t"
+               "mov %%rax, %c[rax](%3) \n\t"
+               "mov %%rbx, %c[rbx](%3) \n\t"
+               "pushq 0(%%rsp); popq %c[rcx](%3) \n\t"
+               "mov %%rdx, %c[rdx](%3) \n\t"
+               "mov %%rsi, %c[rsi](%3) \n\t"
+               "mov %%rdi, %c[rdi](%3) \n\t"
+               "mov %%rbp, %c[rbp](%3) \n\t"
+               "mov %%r8,  %c[r8](%3) \n\t"
+               "mov %%r9,  %c[r9](%3) \n\t"
+               "mov %%r10, %c[r10](%3) \n\t"
+               "mov %%r11, %c[r11](%3) \n\t"
+               "mov %%r12, %c[r12](%3) \n\t"
+               "mov %%r13, %c[r13](%3) \n\t"
+               "mov %%r14, %c[r14](%3) \n\t"
+               "mov %%r15, %c[r15](%3) \n\t"
+               "mov %%cr2, %%rax   \n\t"
+               "mov %%rax, %c[cr2](%3) \n\t"
+               "mov 0(%%rsp), %3 \n\t"
+
+               "pop  %%rcx; pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
+               "pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
+               "pop  %%rbp; pop  %%rdi; pop  %%rsi;"
+               "pop  %%rdx; pop  %%rbx; pop  %%rax \n\t"
+#else
+               "xchg %3, 0(%%esp) \n\t"
+               "mov %%eax, %c[rax](%3) \n\t"
+               "mov %%ebx, %c[rbx](%3) \n\t"
+               "pushl 0(%%esp); popl %c[rcx](%3) \n\t"
+               "mov %%edx, %c[rdx](%3) \n\t"
+               "mov %%esi, %c[rsi](%3) \n\t"
+               "mov %%edi, %c[rdi](%3) \n\t"
+               "mov %%ebp, %c[rbp](%3) \n\t"
+               "mov %%cr2, %%eax  \n\t"
+               "mov %%eax, %c[cr2](%3) \n\t"
+               "mov 0(%%esp), %3 \n\t"
+
+               "pop %%ecx; popa \n\t"
+#endif
+               "setbe %0 \n\t"
+               "popf \n\t"
+             : "=g" (fail)
+             : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
+               "c"(vcpu),
+               [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
+               [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
+               [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
+               [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
+               [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
+               [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
+               [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])),
+#ifdef __x86_64__
+               [r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
+               [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
+               [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
+               [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
+               [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
+               [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
+               [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
+               [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])),
+#endif
+               [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
+             : "cc", "memory" );
+
+       ++kvm_stat.exits;
+
+       save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+       load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+
+       fx_save(vcpu->guest_fx_image);
+       fx_restore(vcpu->host_fx_image);
+
+#ifndef __x86_64__
+       asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
+#endif
+
+       kvm_run->exit_type = 0;
+       if (fail) {
+               kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
+               kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR);
+       } else {
+               if (fs_gs_ldt_reload_needed) {
+                       load_ldt(ldt_sel);
+                       load_fs(fs_sel);
+                       /*
+                        * If we have to reload gs, we must take care to
+                        * preserve our gs base.
+                        */
+                       local_irq_disable();
+                       load_gs(gs_sel);
+#ifdef __x86_64__
+                       wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+#endif
+                       local_irq_enable();
+
+                       reload_tss();
+               }
+               vcpu->launched = 1;
+               kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
+               if (kvm_handle_exit(kvm_run, vcpu)) {
+                       /* Give scheduler a change to reschedule. */
+                       if (signal_pending(current)) {
+                               ++kvm_stat.signal_exits;
+                               return -EINTR;
+                       }
+                       kvm_resched(vcpu);
+                       goto again;
+               }
+       }
+       return 0;
+}
+
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+       vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
+}
+
+static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
+                                 unsigned long addr,
+                                 u32 err_code)
+{
+       u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+
+       ++kvm_stat.pf_guest;
+
+       if (is_page_fault(vect_info)) {
+               printk(KERN_DEBUG "inject_page_fault: "
+                      "double fault 0x%lx @ 0x%lx\n",
+                      addr, vmcs_readl(GUEST_RIP));
+               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                            DF_VECTOR |
+                            INTR_TYPE_EXCEPTION |
+                            INTR_INFO_DELIEVER_CODE_MASK |
+                            INTR_INFO_VALID_MASK);
+               return;
+       }
+       vcpu->cr2 = addr;
+       vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code);
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                    PF_VECTOR |
+                    INTR_TYPE_EXCEPTION |
+                    INTR_INFO_DELIEVER_CODE_MASK |
+                    INTR_INFO_VALID_MASK);
+
+}
+
+static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->vmcs) {
+               on_each_cpu(__vcpu_clear, vcpu, 0, 1);
+               free_vmcs(vcpu->vmcs);
+               vcpu->vmcs = NULL;
+       }
+}
+
+static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
+{
+       vmx_free_vmcs(vcpu);
+}
+
+static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
+{
+       struct vmcs *vmcs;
+
+       vmcs = alloc_vmcs();
+       if (!vmcs)
+               return -ENOMEM;
+       vmcs_clear(vmcs);
+       vcpu->vmcs = vmcs;
+       vcpu->launched = 0;
+       return 0;
+}
+
+static struct kvm_arch_ops vmx_arch_ops = {
+       .cpu_has_kvm_support = cpu_has_kvm_support,
+       .disabled_by_bios = vmx_disabled_by_bios,
+       .hardware_setup = hardware_setup,
+       .hardware_unsetup = hardware_unsetup,
+       .hardware_enable = hardware_enable,
+       .hardware_disable = hardware_disable,
+
+       .vcpu_create = vmx_create_vcpu,
+       .vcpu_free = vmx_free_vcpu,
+
+       .vcpu_load = vmx_vcpu_load,
+       .vcpu_put = vmx_vcpu_put,
+
+       .set_guest_debug = set_guest_debug,
+       .get_msr = vmx_get_msr,
+       .set_msr = vmx_set_msr,
+       .get_segment_base = vmx_get_segment_base,
+       .get_segment = vmx_get_segment,
+       .set_segment = vmx_set_segment,
+       .is_long_mode = vmx_is_long_mode,
+       .get_cs_db_l_bits = vmx_get_cs_db_l_bits,
+       .set_cr0 = vmx_set_cr0,
+       .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
+       .set_cr3 = vmx_set_cr3,
+       .set_cr4 = vmx_set_cr4,
+#ifdef __x86_64__
+       .set_efer = vmx_set_efer,
+#endif
+       .get_idt = vmx_get_idt,
+       .set_idt = vmx_set_idt,
+       .get_gdt = vmx_get_gdt,
+       .set_gdt = vmx_set_gdt,
+       .cache_regs = vcpu_load_rsp_rip,
+       .decache_regs = vcpu_put_rsp_rip,
+       .get_rflags = vmx_get_rflags,
+       .set_rflags = vmx_set_rflags,
+
+       .tlb_flush = vmx_flush_tlb,
+       .inject_page_fault = vmx_inject_page_fault,
+
+       .inject_gp = vmx_inject_gp,
+
+       .run = vmx_vcpu_run,
+       .skip_emulated_instruction = skip_emulated_instruction,
+       .vcpu_setup = vmx_vcpu_setup,
+};
+
+static int __init vmx_init(void)
+{
+       kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+       return 0;
+}
+
+static void __exit vmx_exit(void)
+{
+       kvm_exit_arch();
+}
+
+module_init(vmx_init)
+module_exit(vmx_exit)
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
new file mode 100644 (file)
index 0000000..7972783
--- /dev/null
@@ -0,0 +1,296 @@
+#ifndef VMX_H
+#define VMX_H
+
+/*
+ * vmx.h: VMX Architecture related definitions
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * A few random additions are:
+ * Copyright (C) 2006 Qumranet
+ *    Avi Kivity <avi@qumranet.com>
+ *    Yaniv Kamay <yaniv@qumranet.com>
+ *
+ */
+
+#define CPU_BASED_VIRTUAL_INTR_PENDING  0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING     0x00000008
+#define CPU_BASED_HLT_EXITING           0x00000080
+#define CPU_BASED_INVDPG_EXITING        0x00000200
+#define CPU_BASED_MWAIT_EXITING         0x00000400
+#define CPU_BASED_RDPMC_EXITING         0x00000800
+#define CPU_BASED_RDTSC_EXITING         0x00001000
+#define CPU_BASED_CR8_LOAD_EXITING      0x00080000
+#define CPU_BASED_CR8_STORE_EXITING     0x00100000
+#define CPU_BASED_TPR_SHADOW            0x00200000
+#define CPU_BASED_MOV_DR_EXITING        0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING     0x01000000
+#define CPU_BASED_ACTIVATE_IO_BITMAP    0x02000000
+#define CPU_BASED_MSR_BITMAPS           0x10000000
+#define CPU_BASED_MONITOR_EXITING       0x20000000
+#define CPU_BASED_PAUSE_EXITING         0x40000000
+
+#define PIN_BASED_EXT_INTR_MASK 0x1
+#define PIN_BASED_NMI_EXITING   0x8
+
+#define VM_EXIT_ACK_INTR_ON_EXIT        0x00008000
+#define VM_EXIT_HOST_ADD_SPACE_SIZE     0x00000200
+
+
+/* VMCS Encodings */
+enum vmcs_field {
+       GUEST_ES_SELECTOR               = 0x00000800,
+       GUEST_CS_SELECTOR               = 0x00000802,
+       GUEST_SS_SELECTOR               = 0x00000804,
+       GUEST_DS_SELECTOR               = 0x00000806,
+       GUEST_FS_SELECTOR               = 0x00000808,
+       GUEST_GS_SELECTOR               = 0x0000080a,
+       GUEST_LDTR_SELECTOR             = 0x0000080c,
+       GUEST_TR_SELECTOR               = 0x0000080e,
+       HOST_ES_SELECTOR                = 0x00000c00,
+       HOST_CS_SELECTOR                = 0x00000c02,
+       HOST_SS_SELECTOR                = 0x00000c04,
+       HOST_DS_SELECTOR                = 0x00000c06,
+       HOST_FS_SELECTOR                = 0x00000c08,
+       HOST_GS_SELECTOR                = 0x00000c0a,
+       HOST_TR_SELECTOR                = 0x00000c0c,
+       IO_BITMAP_A                     = 0x00002000,
+       IO_BITMAP_A_HIGH                = 0x00002001,
+       IO_BITMAP_B                     = 0x00002002,
+       IO_BITMAP_B_HIGH                = 0x00002003,
+       MSR_BITMAP                      = 0x00002004,
+       MSR_BITMAP_HIGH                 = 0x00002005,
+       VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
+       VM_EXIT_MSR_STORE_ADDR_HIGH     = 0x00002007,
+       VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
+       VM_EXIT_MSR_LOAD_ADDR_HIGH      = 0x00002009,
+       VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
+       VM_ENTRY_MSR_LOAD_ADDR_HIGH     = 0x0000200b,
+       TSC_OFFSET                      = 0x00002010,
+       TSC_OFFSET_HIGH                 = 0x00002011,
+       VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
+       VIRTUAL_APIC_PAGE_ADDR_HIGH     = 0x00002013,
+       VMCS_LINK_POINTER               = 0x00002800,
+       VMCS_LINK_POINTER_HIGH          = 0x00002801,
+       GUEST_IA32_DEBUGCTL             = 0x00002802,
+       GUEST_IA32_DEBUGCTL_HIGH        = 0x00002803,
+       PIN_BASED_VM_EXEC_CONTROL       = 0x00004000,
+       CPU_BASED_VM_EXEC_CONTROL       = 0x00004002,
+       EXCEPTION_BITMAP                = 0x00004004,
+       PAGE_FAULT_ERROR_CODE_MASK      = 0x00004006,
+       PAGE_FAULT_ERROR_CODE_MATCH     = 0x00004008,
+       CR3_TARGET_COUNT                = 0x0000400a,
+       VM_EXIT_CONTROLS                = 0x0000400c,
+       VM_EXIT_MSR_STORE_COUNT         = 0x0000400e,
+       VM_EXIT_MSR_LOAD_COUNT          = 0x00004010,
+       VM_ENTRY_CONTROLS               = 0x00004012,
+       VM_ENTRY_MSR_LOAD_COUNT         = 0x00004014,
+       VM_ENTRY_INTR_INFO_FIELD        = 0x00004016,
+       VM_ENTRY_EXCEPTION_ERROR_CODE   = 0x00004018,
+       VM_ENTRY_INSTRUCTION_LEN        = 0x0000401a,
+       TPR_THRESHOLD                   = 0x0000401c,
+       SECONDARY_VM_EXEC_CONTROL       = 0x0000401e,
+       VM_INSTRUCTION_ERROR            = 0x00004400,
+       VM_EXIT_REASON                  = 0x00004402,
+       VM_EXIT_INTR_INFO               = 0x00004404,
+       VM_EXIT_INTR_ERROR_CODE         = 0x00004406,
+       IDT_VECTORING_INFO_FIELD        = 0x00004408,
+       IDT_VECTORING_ERROR_CODE        = 0x0000440a,
+       VM_EXIT_INSTRUCTION_LEN         = 0x0000440c,
+       VMX_INSTRUCTION_INFO            = 0x0000440e,
+       GUEST_ES_LIMIT                  = 0x00004800,
+       GUEST_CS_LIMIT                  = 0x00004802,
+       GUEST_SS_LIMIT                  = 0x00004804,
+       GUEST_DS_LIMIT                  = 0x00004806,
+       GUEST_FS_LIMIT                  = 0x00004808,
+       GUEST_GS_LIMIT                  = 0x0000480a,
+       GUEST_LDTR_LIMIT                = 0x0000480c,
+       GUEST_TR_LIMIT                  = 0x0000480e,
+       GUEST_GDTR_LIMIT                = 0x00004810,
+       GUEST_IDTR_LIMIT                = 0x00004812,
+       GUEST_ES_AR_BYTES               = 0x00004814,
+       GUEST_CS_AR_BYTES               = 0x00004816,
+       GUEST_SS_AR_BYTES               = 0x00004818,
+       GUEST_DS_AR_BYTES               = 0x0000481a,
+       GUEST_FS_AR_BYTES               = 0x0000481c,
+       GUEST_GS_AR_BYTES               = 0x0000481e,
+       GUEST_LDTR_AR_BYTES             = 0x00004820,
+       GUEST_TR_AR_BYTES               = 0x00004822,
+       GUEST_INTERRUPTIBILITY_INFO     = 0x00004824,
+       GUEST_ACTIVITY_STATE            = 0X00004826,
+       GUEST_SYSENTER_CS               = 0x0000482A,
+       HOST_IA32_SYSENTER_CS           = 0x00004c00,
+       CR0_GUEST_HOST_MASK             = 0x00006000,
+       CR4_GUEST_HOST_MASK             = 0x00006002,
+       CR0_READ_SHADOW                 = 0x00006004,
+       CR4_READ_SHADOW                 = 0x00006006,
+       CR3_TARGET_VALUE0               = 0x00006008,
+       CR3_TARGET_VALUE1               = 0x0000600a,
+       CR3_TARGET_VALUE2               = 0x0000600c,
+       CR3_TARGET_VALUE3               = 0x0000600e,
+       EXIT_QUALIFICATION              = 0x00006400,
+       GUEST_LINEAR_ADDRESS            = 0x0000640a,
+       GUEST_CR0                       = 0x00006800,
+       GUEST_CR3                       = 0x00006802,
+       GUEST_CR4                       = 0x00006804,
+       GUEST_ES_BASE                   = 0x00006806,
+       GUEST_CS_BASE                   = 0x00006808,
+       GUEST_SS_BASE                   = 0x0000680a,
+       GUEST_DS_BASE                   = 0x0000680c,
+       GUEST_FS_BASE                   = 0x0000680e,
+       GUEST_GS_BASE                   = 0x00006810,
+       GUEST_LDTR_BASE                 = 0x00006812,
+       GUEST_TR_BASE                   = 0x00006814,
+       GUEST_GDTR_BASE                 = 0x00006816,
+       GUEST_IDTR_BASE                 = 0x00006818,
+       GUEST_DR7                       = 0x0000681a,
+       GUEST_RSP                       = 0x0000681c,
+       GUEST_RIP                       = 0x0000681e,
+       GUEST_RFLAGS                    = 0x00006820,
+       GUEST_PENDING_DBG_EXCEPTIONS    = 0x00006822,
+       GUEST_SYSENTER_ESP              = 0x00006824,
+       GUEST_SYSENTER_EIP              = 0x00006826,
+       HOST_CR0                        = 0x00006c00,
+       HOST_CR3                        = 0x00006c02,
+       HOST_CR4                        = 0x00006c04,
+       HOST_FS_BASE                    = 0x00006c06,
+       HOST_GS_BASE                    = 0x00006c08,
+       HOST_TR_BASE                    = 0x00006c0a,
+       HOST_GDTR_BASE                  = 0x00006c0c,
+       HOST_IDTR_BASE                  = 0x00006c0e,
+       HOST_IA32_SYSENTER_ESP          = 0x00006c10,
+       HOST_IA32_SYSENTER_EIP          = 0x00006c12,
+       HOST_RSP                        = 0x00006c14,
+       HOST_RIP                        = 0x00006c16,
+};
+
+#define VMX_EXIT_REASONS_FAILED_VMENTRY         0x80000000
+
+#define EXIT_REASON_EXCEPTION_NMI       0
+#define EXIT_REASON_EXTERNAL_INTERRUPT  1
+
+#define EXIT_REASON_PENDING_INTERRUPT   7
+
+#define EXIT_REASON_TASK_SWITCH         9
+#define EXIT_REASON_CPUID               10
+#define EXIT_REASON_HLT                 12
+#define EXIT_REASON_INVLPG              14
+#define EXIT_REASON_RDPMC               15
+#define EXIT_REASON_RDTSC               16
+#define EXIT_REASON_VMCALL              18
+#define EXIT_REASON_VMCLEAR             19
+#define EXIT_REASON_VMLAUNCH            20
+#define EXIT_REASON_VMPTRLD             21
+#define EXIT_REASON_VMPTRST             22
+#define EXIT_REASON_VMREAD              23
+#define EXIT_REASON_VMRESUME            24
+#define EXIT_REASON_VMWRITE             25
+#define EXIT_REASON_VMOFF               26
+#define EXIT_REASON_VMON                27
+#define EXIT_REASON_CR_ACCESS           28
+#define EXIT_REASON_DR_ACCESS           29
+#define EXIT_REASON_IO_INSTRUCTION      30
+#define EXIT_REASON_MSR_READ            31
+#define EXIT_REASON_MSR_WRITE           32
+#define EXIT_REASON_MWAIT_INSTRUCTION   36
+
+/*
+ * Interruption-information format
+ */
+#define INTR_INFO_VECTOR_MASK           0xff            /* 7:0 */
+#define INTR_INFO_INTR_TYPE_MASK        0x700           /* 10:8 */
+#define INTR_INFO_DELIEVER_CODE_MASK    0x800           /* 11 */
+#define INTR_INFO_VALID_MASK            0x80000000      /* 31 */
+
+#define VECTORING_INFO_VECTOR_MASK             INTR_INFO_VECTOR_MASK
+#define VECTORING_INFO_TYPE_MASK               INTR_INFO_INTR_TYPE_MASK
+#define VECTORING_INFO_DELIEVER_CODE_MASK      INTR_INFO_DELIEVER_CODE_MASK
+#define VECTORING_INFO_VALID_MASK              INTR_INFO_VALID_MASK
+
+#define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
+#define INTR_TYPE_EXCEPTION             (3 << 8) /* processor exception */
+
+/*
+ * Exit Qualifications for MOV for Control Register Access
+ */
+#define CONTROL_REG_ACCESS_NUM          0x7     /* 2:0, number of control register */
+#define CONTROL_REG_ACCESS_TYPE         0x30    /* 5:4, access type */
+#define CONTROL_REG_ACCESS_REG          0xf00   /* 10:8, general purpose register */
+#define LMSW_SOURCE_DATA_SHIFT 16
+#define LMSW_SOURCE_DATA  (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */
+#define REG_EAX                         (0 << 8)
+#define REG_ECX                         (1 << 8)
+#define REG_EDX                         (2 << 8)
+#define REG_EBX                         (3 << 8)
+#define REG_ESP                         (4 << 8)
+#define REG_EBP                         (5 << 8)
+#define REG_ESI                         (6 << 8)
+#define REG_EDI                         (7 << 8)
+#define REG_R8                         (8 << 8)
+#define REG_R9                         (9 << 8)
+#define REG_R10                        (10 << 8)
+#define REG_R11                        (11 << 8)
+#define REG_R12                        (12 << 8)
+#define REG_R13                        (13 << 8)
+#define REG_R14                        (14 << 8)
+#define REG_R15                        (15 << 8)
+
+/*
+ * Exit Qualifications for MOV for Debug Register Access
+ */
+#define DEBUG_REG_ACCESS_NUM            0x7     /* 2:0, number of debug register */
+#define DEBUG_REG_ACCESS_TYPE           0x10    /* 4, direction of access */
+#define TYPE_MOV_TO_DR                  (0 << 4)
+#define TYPE_MOV_FROM_DR                (1 << 4)
+#define DEBUG_REG_ACCESS_REG            0xf00   /* 11:8, general purpose register */
+
+
+/* segment AR */
+#define SEGMENT_AR_L_MASK (1 << 13)
+
+/* entry controls */
+#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9)
+
+#define AR_TYPE_ACCESSES_MASK 1
+#define AR_TYPE_READABLE_MASK (1 << 1)
+#define AR_TYPE_WRITEABLE_MASK (1 << 2)
+#define AR_TYPE_CODE_MASK (1 << 3)
+#define AR_TYPE_MASK 0x0f
+#define AR_TYPE_BUSY_64_TSS 11
+#define AR_TYPE_BUSY_32_TSS 11
+#define AR_TYPE_BUSY_16_TSS 3
+#define AR_TYPE_LDT 2
+
+#define AR_UNUSABLE_MASK (1 << 16)
+#define AR_S_MASK (1 << 4)
+#define AR_P_MASK (1 << 7)
+#define AR_L_MASK (1 << 13)
+#define AR_DB_MASK (1 << 14)
+#define AR_G_MASK (1 << 15)
+#define AR_DPL_SHIFT 5
+#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3)
+
+#define AR_RESERVD_MASK 0xfffe0f00
+
+#define CR4_VMXE 0x2000
+
+#define MSR_IA32_VMX_BASIC_MSR                 0x480
+#define MSR_IA32_FEATURE_CONTROL               0x03a
+#define MSR_IA32_VMX_PINBASED_CTLS_MSR         0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS_MSR                0x482
+#define MSR_IA32_VMX_EXIT_CTLS_MSR             0x483
+#define MSR_IA32_VMX_ENTRY_CTLS_MSR            0x484
+
+#endif
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
new file mode 100644 (file)
index 0000000..7e838bf
--- /dev/null
@@ -0,0 +1,1409 @@
+/******************************************************************************
+ * x86_emulate.c
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * Linux coding style, mod r/m decoder, segment base fixes, real-mode
+ * privieged instructions:
+ *
+ * Copyright (C) 2006 Qumranet
+ *
+ *   Avi Kivity <avi@qumranet.com>
+ *   Yaniv Kamay <yaniv@qumranet.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
+ */
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <stdint.h>
+#include <public/xen.h>
+#define DPRINTF(_f, _a ...) printf( _f , ## _a )
+#else
+#include "kvm.h"
+#define DPRINTF(x...) do {} while (0)
+#endif
+#include "x86_emulate.h"
+#include <linux/module.h>
+
+/*
+ * Opcode effective-address decode tables.
+ * Note that we only emulate instructions that have at least one memory
+ * operand (excluding implicit stack references). We assume that stack
+ * references and instruction fetches will never occur in special memory
+ * areas that require emulation. So, for example, 'mov <imm>,<reg>' need
+ * not be handled.
+ */
+
+/* Operand sizes: 8-bit operands or specified/overridden size. */
+#define ByteOp      (1<<0)     /* 8-bit operands. */
+/* Destination operand type. */
+#define ImplicitOps (1<<1)     /* Implicit in opcode. No generic decode. */
+#define DstReg      (2<<1)     /* Register operand. */
+#define DstMem      (3<<1)     /* Memory operand. */
+#define DstMask     (3<<1)
+/* Source operand type. */
+#define SrcNone     (0<<3)     /* No source operand. */
+#define SrcImplicit (0<<3)     /* Source operand is implicit in the opcode. */
+#define SrcReg      (1<<3)     /* Register operand. */
+#define SrcMem      (2<<3)     /* Memory operand. */
+#define SrcMem16    (3<<3)     /* Memory operand (16-bit). */
+#define SrcMem32    (4<<3)     /* Memory operand (32-bit). */
+#define SrcImm      (5<<3)     /* Immediate operand. */
+#define SrcImmByte  (6<<3)     /* 8-bit sign-extended immediate operand. */
+#define SrcMask     (7<<3)
+/* Generic ModRM decode. */
+#define ModRM       (1<<6)
+/* Destination is only written; never read. */
+#define Mov         (1<<7)
+
+static u8 opcode_table[256] = {
+       /* 0x00 - 0x07 */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x08 - 0x0F */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x10 - 0x17 */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x18 - 0x1F */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x20 - 0x27 */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x28 - 0x2F */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x30 - 0x37 */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x38 - 0x3F */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
+       0, 0, 0, 0,
+       /* 0x40 - 0x4F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x50 - 0x5F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x60 - 0x6F */
+       0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x70 - 0x7F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x80 - 0x87 */
+       ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+       ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       /* 0x88 - 0x8F */
+       ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
+       ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       0, 0, 0, DstMem | SrcNone | ModRM | Mov,
+       /* 0x90 - 0x9F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xA0 - 0xA7 */
+       ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
+       ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
+       ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+       ByteOp | ImplicitOps, ImplicitOps,
+       /* 0xA8 - 0xAF */
+       0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+       ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
+       ByteOp | ImplicitOps, ImplicitOps,
+       /* 0xB0 - 0xBF */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xC0 - 0xC7 */
+       ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, 0,
+       0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov,
+           DstMem | SrcImm | ModRM | Mov,
+       /* 0xC8 - 0xCF */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xD0 - 0xD7 */
+       ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
+       ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
+       0, 0, 0, 0,
+       /* 0xD8 - 0xDF */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xE0 - 0xEF */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xF0 - 0xF7 */
+       0, 0, 0, 0,
+       0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+       /* 0xF8 - 0xFF */
+       0, 0, 0, 0,
+       0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
+};
+
+static u8 twobyte_table[256] = {
+       /* 0x00 - 0x0F */
+       0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
+       0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+       /* 0x10 - 0x1F */
+       0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x20 - 0x2F */
+       ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x30 - 0x3F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x40 - 0x47 */
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       /* 0x48 - 0x4F */
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
+       /* 0x50 - 0x5F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x60 - 0x6F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x70 - 0x7F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x80 - 0x8F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0x90 - 0x9F */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xA0 - 0xA7 */
+       0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0,
+       /* 0xA8 - 0xAF */
+       0, 0, 0, DstMem | SrcReg | ModRM, 0, 0, 0, 0,
+       /* 0xB0 - 0xB7 */
+       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0,
+           DstMem | SrcReg | ModRM,
+       0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
+           DstReg | SrcMem16 | ModRM | Mov,
+       /* 0xB8 - 0xBF */
+       0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM,
+       0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
+           DstReg | SrcMem16 | ModRM | Mov,
+       /* 0xC0 - 0xCF */
+       0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xD0 - 0xDF */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xE0 - 0xEF */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       /* 0xF0 - 0xFF */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we
+ * are interested only in invlpg and not in any of the rest.
+ *
+ * invlpg is a special instruction in that the data it references may not
+ * be mapped.
+ */
+void kvm_emulator_want_group7_invlpg(void)
+{
+       twobyte_table[1] &= ~SrcMem;
+}
+EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg);
+
+/* Type, address-of, and value of an instruction's operand. */
+struct operand {
+       enum { OP_REG, OP_MEM, OP_IMM } type;
+       unsigned int bytes;
+       unsigned long val, orig_val, *ptr;
+};
+
+/* EFLAGS bit definitions. */
+#define EFLG_OF (1<<11)
+#define EFLG_DF (1<<10)
+#define EFLG_SF (1<<7)
+#define EFLG_ZF (1<<6)
+#define EFLG_AF (1<<4)
+#define EFLG_PF (1<<2)
+#define EFLG_CF (1<<0)
+
+/*
+ * Instruction emulation:
+ * Most instructions are emulated directly via a fragment of inline assembly
+ * code. This allows us to save/restore EFLAGS and thus very easily pick up
+ * any modified flags.
+ */
+
+#if defined(__x86_64__)
+#define _LO32 "k"              /* force 32-bit operand */
+#define _STK  "%%rsp"          /* stack pointer */
+#elif defined(__i386__)
+#define _LO32 ""               /* force 32-bit operand */
+#define _STK  "%%esp"          /* stack pointer */
+#endif
+
+/*
+ * These EFLAGS bits are restored from saved value during emulation, and
+ * any changes are written back to the saved value after emulation.
+ */
+#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
+
+/* Before executing instruction: restore necessary bits in EFLAGS. */
+#define _PRE_EFLAGS(_sav, _msk, _tmp) \
+       /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */        \
+       "push %"_sav"; "                                        \
+       "movl %"_msk",%"_LO32 _tmp"; "                          \
+       "andl %"_LO32 _tmp",("_STK"); "                         \
+       "pushf; "                                               \
+       "notl %"_LO32 _tmp"; "                                  \
+       "andl %"_LO32 _tmp",("_STK"); "                         \
+       "pop  %"_tmp"; "                                        \
+       "orl  %"_LO32 _tmp",("_STK"); "                         \
+       "popf; "                                                \
+       /* _sav &= ~msk; */                                     \
+       "movl %"_msk",%"_LO32 _tmp"; "                          \
+       "notl %"_LO32 _tmp"; "                                  \
+       "andl %"_LO32 _tmp",%"_sav"; "
+
+/* After executing instruction: write-back necessary bits in EFLAGS. */
+#define _POST_EFLAGS(_sav, _msk, _tmp) \
+       /* _sav |= EFLAGS & _msk; */            \
+       "pushf; "                               \
+       "pop  %"_tmp"; "                        \
+       "andl %"_msk",%"_LO32 _tmp"; "          \
+       "orl  %"_LO32 _tmp",%"_sav"; "
+
+/* Raw emulation: instruction has two explicit operands. */
+#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \
+       do {                                                                \
+               unsigned long _tmp;                                         \
+                                                                           \
+               switch ((_dst).bytes) {                                     \
+               case 2:                                                     \
+                       __asm__ __volatile__ (                              \
+                               _PRE_EFLAGS("0","4","2")                    \
+                               _op"w %"_wx"3,%1; "                         \
+                               _POST_EFLAGS("0","4","2")                   \
+                               : "=m" (_eflags), "=m" ((_dst).val),        \
+                                 "=&r" (_tmp)                              \
+                               : _wy ((_src).val), "i" (EFLAGS_MASK) );    \
+                       break;                                              \
+               case 4:                                                     \
+                       __asm__ __volatile__ (                              \
+                               _PRE_EFLAGS("0","4","2")                    \
+                               _op"l %"_lx"3,%1; "                         \
+                               _POST_EFLAGS("0","4","2")                   \
+                               : "=m" (_eflags), "=m" ((_dst).val),        \
+                                 "=&r" (_tmp)                              \
+                               : _ly ((_src).val), "i" (EFLAGS_MASK) );    \
+                       break;                                              \
+               case 8:                                                     \
+                       __emulate_2op_8byte(_op, _src, _dst,                \
+                                           _eflags, _qx, _qy);             \
+                       break;                                              \
+               }                                                           \
+       } while (0)
+
+#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
+       do {                                                                 \
+               unsigned long _tmp;                                          \
+               switch ( (_dst).bytes )                                      \
+               {                                                            \
+               case 1:                                                      \
+                       __asm__ __volatile__ (                               \
+                               _PRE_EFLAGS("0","4","2")                     \
+                               _op"b %"_bx"3,%1; "                          \
+                               _POST_EFLAGS("0","4","2")                    \
+                               : "=m" (_eflags), "=m" ((_dst).val),         \
+                                 "=&r" (_tmp)                               \
+                               : _by ((_src).val), "i" (EFLAGS_MASK) );     \
+                       break;                                               \
+               default:                                                     \
+                       __emulate_2op_nobyte(_op, _src, _dst, _eflags,       \
+                                            _wx, _wy, _lx, _ly, _qx, _qy);  \
+                       break;                                               \
+               }                                                            \
+       } while (0)
+
+/* Source operand is byte-sized and may be restricted to just %cl. */
+#define emulate_2op_SrcB(_op, _src, _dst, _eflags)                      \
+       __emulate_2op(_op, _src, _dst, _eflags,                         \
+                     "b", "c", "b", "c", "b", "c", "b", "c")
+
+/* Source operand is byte, word, long or quad sized. */
+#define emulate_2op_SrcV(_op, _src, _dst, _eflags)                      \
+       __emulate_2op(_op, _src, _dst, _eflags,                         \
+                     "b", "q", "w", "r", _LO32, "r", "", "r")
+
+/* Source operand is word, long or quad sized. */
+#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags)               \
+       __emulate_2op_nobyte(_op, _src, _dst, _eflags,                  \
+                            "w", "r", _LO32, "r", "", "r")
+
+/* Instruction has only one explicit operand (no source operand). */
+#define emulate_1op(_op, _dst, _eflags)                                    \
+       do {                                                            \
+               unsigned long _tmp;                                     \
+                                                                       \
+               switch ( (_dst).bytes )                                 \
+               {                                                       \
+               case 1:                                                 \
+                       __asm__ __volatile__ (                          \
+                               _PRE_EFLAGS("0","3","2")                \
+                               _op"b %1; "                             \
+                               _POST_EFLAGS("0","3","2")               \
+                               : "=m" (_eflags), "=m" ((_dst).val),    \
+                                 "=&r" (_tmp)                          \
+                               : "i" (EFLAGS_MASK) );                  \
+                       break;                                          \
+               case 2:                                                 \
+                       __asm__ __volatile__ (                          \
+                               _PRE_EFLAGS("0","3","2")                \
+                               _op"w %1; "                             \
+                               _POST_EFLAGS("0","3","2")               \
+                               : "=m" (_eflags), "=m" ((_dst).val),    \
+                                 "=&r" (_tmp)                          \
+                               : "i" (EFLAGS_MASK) );                  \
+                       break;                                          \
+               case 4:                                                 \
+                       __asm__ __volatile__ (                          \
+                               _PRE_EFLAGS("0","3","2")                \
+                               _op"l %1; "                             \
+                               _POST_EFLAGS("0","3","2")               \
+                               : "=m" (_eflags), "=m" ((_dst).val),    \
+                                 "=&r" (_tmp)                          \
+                               : "i" (EFLAGS_MASK) );                  \
+                       break;                                          \
+               case 8:                                                 \
+                       __emulate_1op_8byte(_op, _dst, _eflags);        \
+                       break;                                          \
+               }                                                       \
+       } while (0)
+
+/* Emulate an instruction with quadword operands (x86/64 only). */
+#if defined(__x86_64__)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)           \
+       do {                                                              \
+               __asm__ __volatile__ (                                    \
+                       _PRE_EFLAGS("0","4","2")                          \
+                       _op"q %"_qx"3,%1; "                               \
+                       _POST_EFLAGS("0","4","2")                         \
+                       : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
+                       : _qy ((_src).val), "i" (EFLAGS_MASK) );          \
+       } while (0)
+
+#define __emulate_1op_8byte(_op, _dst, _eflags)                           \
+       do {                                                              \
+               __asm__ __volatile__ (                                    \
+                       _PRE_EFLAGS("0","3","2")                          \
+                       _op"q %1; "                                       \
+                       _POST_EFLAGS("0","3","2")                         \
+                       : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
+                       : "i" (EFLAGS_MASK) );                            \
+       } while (0)
+
+#elif defined(__i386__)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
+#define __emulate_1op_8byte(_op, _dst, _eflags)
+#endif                         /* __i386__ */
+
+/* Fetch next part of the instruction being emulated. */
+#define insn_fetch(_type, _size, _eip)                                  \
+({     unsigned long _x;                                               \
+       rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x,  \
+                                                  (_size), ctxt);       \
+       if ( rc != 0 )                                                  \
+               goto done;                                              \
+       (_eip) += (_size);                                              \
+       (_type)_x;                                                      \
+})
+
+/* Access/update address held in a register, based on addressing mode. */
+#define register_address(base, reg)                                     \
+       ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) :        \
+                  ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
+
+#define register_address_increment(reg, inc)                            \
+       do {                                                            \
+               /* signed type ensures sign extension to long */        \
+               int _inc = (inc);                                       \
+               if ( ad_bytes == sizeof(unsigned long) )                \
+                       (reg) += _inc;                                  \
+               else                                                    \
+                       (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \
+                          (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
+       } while (0)
+
+void *decode_register(u8 modrm_reg, unsigned long *regs,
+                     int highbyte_regs)
+{
+       void *p;
+
+       p = &regs[modrm_reg];
+       if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8)
+               p = (unsigned char *)&regs[modrm_reg & 3] + 1;
+       return p;
+}
+
+static int read_descriptor(struct x86_emulate_ctxt *ctxt,
+                          struct x86_emulate_ops *ops,
+                          void *ptr,
+                          u16 *size, unsigned long *address, int op_bytes)
+{
+       int rc;
+
+       if (op_bytes == 2)
+               op_bytes = 3;
+       *address = 0;
+       rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt);
+       if (rc)
+               return rc;
+       rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt);
+       return rc;
+}
+
+int
+x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+{
+       u8 b, d, sib, twobyte = 0, rex_prefix = 0;
+       u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+       unsigned long *override_base = NULL;
+       unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
+       int rc = 0;
+       struct operand src, dst;
+       unsigned long cr2 = ctxt->cr2;
+       int mode = ctxt->mode;
+       unsigned long modrm_ea;
+       int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
+
+       /* Shadow copy of register state. Committed on successful emulation. */
+       unsigned long _regs[NR_VCPU_REGS];
+       unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags;
+       unsigned long modrm_val = 0;
+
+       memcpy(_regs, ctxt->vcpu->regs, sizeof _regs);
+
+       switch (mode) {
+       case X86EMUL_MODE_REAL:
+       case X86EMUL_MODE_PROT16:
+               op_bytes = ad_bytes = 2;
+               break;
+       case X86EMUL_MODE_PROT32:
+               op_bytes = ad_bytes = 4;
+               break;
+#ifdef __x86_64__
+       case X86EMUL_MODE_PROT64:
+               op_bytes = 4;
+               ad_bytes = 8;
+               break;
+#endif
+       default:
+               return -1;
+       }
+
+       /* Legacy prefixes. */
+       for (i = 0; i < 8; i++) {
+               switch (b = insn_fetch(u8, 1, _eip)) {
+               case 0x66:      /* operand-size override */
+                       op_bytes ^= 6;  /* switch between 2/4 bytes */
+                       break;
+               case 0x67:      /* address-size override */
+                       if (mode == X86EMUL_MODE_PROT64)
+                               ad_bytes ^= 12; /* switch between 4/8 bytes */
+                       else
+                               ad_bytes ^= 6;  /* switch between 2/4 bytes */
+                       break;
+               case 0x2e:      /* CS override */
+                       override_base = &ctxt->cs_base;
+                       break;
+               case 0x3e:      /* DS override */
+                       override_base = &ctxt->ds_base;
+                       break;
+               case 0x26:      /* ES override */
+                       override_base = &ctxt->es_base;
+                       break;
+               case 0x64:      /* FS override */
+                       override_base = &ctxt->fs_base;
+                       break;
+               case 0x65:      /* GS override */
+                       override_base = &ctxt->gs_base;
+                       break;
+               case 0x36:      /* SS override */
+                       override_base = &ctxt->ss_base;
+                       break;
+               case 0xf0:      /* LOCK */
+                       lock_prefix = 1;
+                       break;
+               case 0xf3:      /* REP/REPE/REPZ */
+                       rep_prefix = 1;
+                       break;
+               case 0xf2:      /* REPNE/REPNZ */
+                       break;
+               default:
+                       goto done_prefixes;
+               }
+       }
+
+done_prefixes:
+
+       /* REX prefix. */
+       if ((mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40)) {
+               rex_prefix = b;
+               if (b & 8)
+                       op_bytes = 8;   /* REX.W */
+               modrm_reg = (b & 4) << 1;       /* REX.R */
+               index_reg = (b & 2) << 2; /* REX.X */
+               modrm_rm = base_reg = (b & 1) << 3; /* REG.B */
+               b = insn_fetch(u8, 1, _eip);
+       }
+
+       /* Opcode byte(s). */
+       d = opcode_table[b];
+       if (d == 0) {
+               /* Two-byte opcode? */
+               if (b == 0x0f) {
+                       twobyte = 1;
+                       b = insn_fetch(u8, 1, _eip);
+                       d = twobyte_table[b];
+               }
+
+               /* Unrecognised? */
+               if (d == 0)
+                       goto cannot_emulate;
+       }
+
+       /* ModRM and SIB bytes. */
+       if (d & ModRM) {
+               modrm = insn_fetch(u8, 1, _eip);
+               modrm_mod |= (modrm & 0xc0) >> 6;
+               modrm_reg |= (modrm & 0x38) >> 3;
+               modrm_rm |= (modrm & 0x07);
+               modrm_ea = 0;
+               use_modrm_ea = 1;
+
+               if (modrm_mod == 3) {
+                       modrm_val = *(unsigned long *)
+                               decode_register(modrm_rm, _regs, d & ByteOp);
+                       goto modrm_done;
+               }
+
+               if (ad_bytes == 2) {
+                       unsigned bx = _regs[VCPU_REGS_RBX];
+                       unsigned bp = _regs[VCPU_REGS_RBP];
+                       unsigned si = _regs[VCPU_REGS_RSI];
+                       unsigned di = _regs[VCPU_REGS_RDI];
+
+                       /* 16-bit ModR/M decode. */
+                       switch (modrm_mod) {
+                       case 0:
+                               if (modrm_rm == 6)
+                                       modrm_ea += insn_fetch(u16, 2, _eip);
+                               break;
+                       case 1:
+                               modrm_ea += insn_fetch(s8, 1, _eip);
+                               break;
+                       case 2:
+                               modrm_ea += insn_fetch(u16, 2, _eip);
+                               break;
+                       }
+                       switch (modrm_rm) {
+                       case 0:
+                               modrm_ea += bx + si;
+                               break;
+                       case 1:
+                               modrm_ea += bx + di;
+                               break;
+                       case 2:
+                               modrm_ea += bp + si;
+                               break;
+                       case 3:
+                               modrm_ea += bp + di;
+                               break;
+                       case 4:
+                               modrm_ea += si;
+                               break;
+                       case 5:
+                               modrm_ea += di;
+                               break;
+                       case 6:
+                               if (modrm_mod != 0)
+                                       modrm_ea += bp;
+                               break;
+                       case 7:
+                               modrm_ea += bx;
+                               break;
+                       }
+                       if (modrm_rm == 2 || modrm_rm == 3 ||
+                           (modrm_rm == 6 && modrm_mod != 0))
+                               if (!override_base)
+                                       override_base = &ctxt->ss_base;
+                       modrm_ea = (u16)modrm_ea;
+               } else {
+                       /* 32/64-bit ModR/M decode. */
+                       switch (modrm_rm) {
+                       case 4:
+                       case 12:
+                               sib = insn_fetch(u8, 1, _eip);
+                               index_reg |= (sib >> 3) & 7;
+                               base_reg |= sib & 7;
+                               scale = sib >> 6;
+
+                               switch (base_reg) {
+                               case 5:
+                                       if (modrm_mod != 0)
+                                               modrm_ea += _regs[base_reg];
+                                       else
+                                               modrm_ea += insn_fetch(s32, 4, _eip);
+                                       break;
+                               default:
+                                       modrm_ea += _regs[base_reg];
+                               }
+                               switch (index_reg) {
+                               case 4:
+                                       break;
+                               default:
+                                       modrm_ea += _regs[index_reg] << scale;
+
+                               }
+                               break;
+                       case 5:
+                               if (modrm_mod != 0)
+                                       modrm_ea += _regs[modrm_rm];
+                               else if (mode == X86EMUL_MODE_PROT64)
+                                       rip_relative = 1;
+                               break;
+                       default:
+                               modrm_ea += _regs[modrm_rm];
+                               break;
+                       }
+                       switch (modrm_mod) {
+                       case 0:
+                               if (modrm_rm == 5)
+                                       modrm_ea += insn_fetch(s32, 4, _eip);
+                               break;
+                       case 1:
+                               modrm_ea += insn_fetch(s8, 1, _eip);
+                               break;
+                       case 2:
+                               modrm_ea += insn_fetch(s32, 4, _eip);
+                               break;
+                       }
+               }
+               if (!override_base)
+                       override_base = &ctxt->ds_base;
+               if (mode == X86EMUL_MODE_PROT64 &&
+                   override_base != &ctxt->fs_base &&
+                   override_base != &ctxt->gs_base)
+                       override_base = NULL;
+
+               if (override_base)
+                       modrm_ea += *override_base;
+
+               if (rip_relative) {
+                       modrm_ea += _eip;
+                       switch (d & SrcMask) {
+                       case SrcImmByte:
+                               modrm_ea += 1;
+                               break;
+                       case SrcImm:
+                               if (d & ByteOp)
+                                       modrm_ea += 1;
+                               else
+                                       if (op_bytes == 8)
+                                               modrm_ea += 4;
+                                       else
+                                               modrm_ea += op_bytes;
+                       }
+               }
+               if (ad_bytes != 8)
+                       modrm_ea = (u32)modrm_ea;
+               cr2 = modrm_ea;
+       modrm_done:
+               ;
+       }
+
+       /* Decode and fetch the destination operand: register or memory. */
+       switch (d & DstMask) {
+       case ImplicitOps:
+               /* Special instructions do their own operand decoding. */
+               goto special_insn;
+       case DstReg:
+               dst.type = OP_REG;
+               if ((d & ByteOp)
+                   && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+                       dst.ptr = decode_register(modrm_reg, _regs,
+                                                 (rex_prefix == 0));
+                       dst.val = *(u8 *) dst.ptr;
+                       dst.bytes = 1;
+               } else {
+                       dst.ptr = decode_register(modrm_reg, _regs, 0);
+                       switch ((dst.bytes = op_bytes)) {
+                       case 2:
+                               dst.val = *(u16 *)dst.ptr;
+                               break;
+                       case 4:
+                               dst.val = *(u32 *)dst.ptr;
+                               break;
+                       case 8:
+                               dst.val = *(u64 *)dst.ptr;
+                               break;
+                       }
+               }
+               break;
+       case DstMem:
+               dst.type = OP_MEM;
+               dst.ptr = (unsigned long *)cr2;
+               dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+               if (!(d & Mov) && /* optimisation - avoid slow emulated read */
+                   ((rc = ops->read_emulated((unsigned long)dst.ptr,
+                                             &dst.val, dst.bytes, ctxt)) != 0))
+                       goto done;
+               break;
+       }
+       dst.orig_val = dst.val;
+
+       /*
+        * Decode and fetch the source operand: register, memory
+        * or immediate.
+        */
+       switch (d & SrcMask) {
+       case SrcNone:
+               break;
+       case SrcReg:
+               src.type = OP_REG;
+               if (d & ByteOp) {
+                       src.ptr = decode_register(modrm_reg, _regs,
+                                                 (rex_prefix == 0));
+                       src.val = src.orig_val = *(u8 *) src.ptr;
+                       src.bytes = 1;
+               } else {
+                       src.ptr = decode_register(modrm_reg, _regs, 0);
+                       switch ((src.bytes = op_bytes)) {
+                       case 2:
+                               src.val = src.orig_val = *(u16 *) src.ptr;
+                               break;
+                       case 4:
+                               src.val = src.orig_val = *(u32 *) src.ptr;
+                               break;
+                       case 8:
+                               src.val = src.orig_val = *(u64 *) src.ptr;
+                               break;
+                       }
+               }
+               break;
+       case SrcMem16:
+               src.bytes = 2;
+               goto srcmem_common;
+       case SrcMem32:
+               src.bytes = 4;
+               goto srcmem_common;
+       case SrcMem:
+               src.bytes = (d & ByteOp) ? 1 : op_bytes;
+             srcmem_common:
+               src.type = OP_MEM;
+               src.ptr = (unsigned long *)cr2;
+               if ((rc = ops->read_emulated((unsigned long)src.ptr,
+                                            &src.val, src.bytes, ctxt)) != 0)
+                       goto done;
+               src.orig_val = src.val;
+               break;
+       case SrcImm:
+               src.type = OP_IMM;
+               src.ptr = (unsigned long *)_eip;
+               src.bytes = (d & ByteOp) ? 1 : op_bytes;
+               if (src.bytes == 8)
+                       src.bytes = 4;
+               /* NB. Immediates are sign-extended as necessary. */
+               switch (src.bytes) {
+               case 1:
+                       src.val = insn_fetch(s8, 1, _eip);
+                       break;
+               case 2:
+                       src.val = insn_fetch(s16, 2, _eip);
+                       break;
+               case 4:
+                       src.val = insn_fetch(s32, 4, _eip);
+                       break;
+               }
+               break;
+       case SrcImmByte:
+               src.type = OP_IMM;
+               src.ptr = (unsigned long *)_eip;
+               src.bytes = 1;
+               src.val = insn_fetch(s8, 1, _eip);
+               break;
+       }
+
+       if (twobyte)
+               goto twobyte_insn;
+
+       switch (b) {
+       case 0x00 ... 0x05:
+             add:              /* add */
+               emulate_2op_SrcV("add", src, dst, _eflags);
+               break;
+       case 0x08 ... 0x0d:
+             or:               /* or */
+               emulate_2op_SrcV("or", src, dst, _eflags);
+               break;
+       case 0x10 ... 0x15:
+             adc:              /* adc */
+               emulate_2op_SrcV("adc", src, dst, _eflags);
+               break;
+       case 0x18 ... 0x1d:
+             sbb:              /* sbb */
+               emulate_2op_SrcV("sbb", src, dst, _eflags);
+               break;
+       case 0x20 ... 0x25:
+             and:              /* and */
+               emulate_2op_SrcV("and", src, dst, _eflags);
+               break;
+       case 0x28 ... 0x2d:
+             sub:              /* sub */
+               emulate_2op_SrcV("sub", src, dst, _eflags);
+               break;
+       case 0x30 ... 0x35:
+             xor:              /* xor */
+               emulate_2op_SrcV("xor", src, dst, _eflags);
+               break;
+       case 0x38 ... 0x3d:
+             cmp:              /* cmp */
+               emulate_2op_SrcV("cmp", src, dst, _eflags);
+               break;
+       case 0x63:              /* movsxd */
+               if (mode != X86EMUL_MODE_PROT64)
+                       goto cannot_emulate;
+               dst.val = (s32) src.val;
+               break;
+       case 0x80 ... 0x83:     /* Grp1 */
+               switch (modrm_reg) {
+               case 0:
+                       goto add;
+               case 1:
+                       goto or;
+               case 2:
+                       goto adc;
+               case 3:
+                       goto sbb;
+               case 4:
+                       goto and;
+               case 5:
+                       goto sub;
+               case 6:
+                       goto xor;
+               case 7:
+                       goto cmp;
+               }
+               break;
+       case 0x84 ... 0x85:
+             test:             /* test */
+               emulate_2op_SrcV("test", src, dst, _eflags);
+               break;
+       case 0x86 ... 0x87:     /* xchg */
+               /* Write back the register source. */
+               switch (dst.bytes) {
+               case 1:
+                       *(u8 *) src.ptr = (u8) dst.val;
+                       break;
+               case 2:
+                       *(u16 *) src.ptr = (u16) dst.val;
+                       break;
+               case 4:
+                       *src.ptr = (u32) dst.val;
+                       break;  /* 64b reg: zero-extend */
+               case 8:
+                       *src.ptr = dst.val;
+                       break;
+               }
+               /*
+                * Write back the memory destination with implicit LOCK
+                * prefix.
+                */
+               dst.val = src.val;
+               lock_prefix = 1;
+               break;
+       case 0xa0 ... 0xa1:     /* mov */
+               dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+               dst.val = src.val;
+               _eip += ad_bytes;       /* skip src displacement */
+               break;
+       case 0xa2 ... 0xa3:     /* mov */
+               dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
+               _eip += ad_bytes;       /* skip dst displacement */
+               break;
+       case 0x88 ... 0x8b:     /* mov */
+       case 0xc6 ... 0xc7:     /* mov (sole member of Grp11) */
+               dst.val = src.val;
+               break;
+       case 0x8f:              /* pop (sole member of Grp1a) */
+               /* 64-bit mode: POP always pops a 64-bit operand. */
+               if (mode == X86EMUL_MODE_PROT64)
+                       dst.bytes = 8;
+               if ((rc = ops->read_std(register_address(ctxt->ss_base,
+                                                        _regs[VCPU_REGS_RSP]),
+                                       &dst.val, dst.bytes, ctxt)) != 0)
+                       goto done;
+               register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
+               break;
+       case 0xc0 ... 0xc1:
+             grp2:             /* Grp2 */
+               switch (modrm_reg) {
+               case 0: /* rol */
+                       emulate_2op_SrcB("rol", src, dst, _eflags);
+                       break;
+               case 1: /* ror */
+                       emulate_2op_SrcB("ror", src, dst, _eflags);
+                       break;
+               case 2: /* rcl */
+                       emulate_2op_SrcB("rcl", src, dst, _eflags);
+                       break;
+               case 3: /* rcr */
+                       emulate_2op_SrcB("rcr", src, dst, _eflags);
+                       break;
+               case 4: /* sal/shl */
+               case 6: /* sal/shl */
+                       emulate_2op_SrcB("sal", src, dst, _eflags);
+                       break;
+               case 5: /* shr */
+                       emulate_2op_SrcB("shr", src, dst, _eflags);
+                       break;
+               case 7: /* sar */
+                       emulate_2op_SrcB("sar", src, dst, _eflags);
+                       break;
+               }
+               break;
+       case 0xd0 ... 0xd1:     /* Grp2 */
+               src.val = 1;
+               goto grp2;
+       case 0xd2 ... 0xd3:     /* Grp2 */
+               src.val = _regs[VCPU_REGS_RCX];
+               goto grp2;
+       case 0xf6 ... 0xf7:     /* Grp3 */
+               switch (modrm_reg) {
+               case 0 ... 1:   /* test */
+                       /*
+                        * Special case in Grp3: test has an immediate
+                        * source operand.
+                        */
+                       src.type = OP_IMM;
+                       src.ptr = (unsigned long *)_eip;
+                       src.bytes = (d & ByteOp) ? 1 : op_bytes;
+                       if (src.bytes == 8)
+                               src.bytes = 4;
+                       switch (src.bytes) {
+                       case 1:
+                               src.val = insn_fetch(s8, 1, _eip);
+                               break;
+                       case 2:
+                               src.val = insn_fetch(s16, 2, _eip);
+                               break;
+                       case 4:
+                               src.val = insn_fetch(s32, 4, _eip);
+                               break;
+                       }
+                       goto test;
+               case 2: /* not */
+                       dst.val = ~dst.val;
+                       break;
+               case 3: /* neg */
+                       emulate_1op("neg", dst, _eflags);
+                       break;
+               default:
+                       goto cannot_emulate;
+               }
+               break;
+       case 0xfe ... 0xff:     /* Grp4/Grp5 */
+               switch (modrm_reg) {
+               case 0: /* inc */
+                       emulate_1op("inc", dst, _eflags);
+                       break;
+               case 1: /* dec */
+                       emulate_1op("dec", dst, _eflags);
+                       break;
+               case 6: /* push */
+                       /* 64-bit mode: PUSH always pushes a 64-bit operand. */
+                       if (mode == X86EMUL_MODE_PROT64) {
+                               dst.bytes = 8;
+                               if ((rc = ops->read_std((unsigned long)dst.ptr,
+                                                       &dst.val, 8,
+                                                       ctxt)) != 0)
+                                       goto done;
+                       }
+                       register_address_increment(_regs[VCPU_REGS_RSP],
+                                                  -dst.bytes);
+                       if ((rc = ops->write_std(
+                                    register_address(ctxt->ss_base,
+                                                     _regs[VCPU_REGS_RSP]),
+                                    dst.val, dst.bytes, ctxt)) != 0)
+                               goto done;
+                       dst.val = dst.orig_val; /* skanky: disable writeback */
+                       break;
+               default:
+                       goto cannot_emulate;
+               }
+               break;
+       }
+
+writeback:
+       if ((d & Mov) || (dst.orig_val != dst.val)) {
+               switch (dst.type) {
+               case OP_REG:
+                       /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+                       switch (dst.bytes) {
+                       case 1:
+                               *(u8 *)dst.ptr = (u8)dst.val;
+                               break;
+                       case 2:
+                               *(u16 *)dst.ptr = (u16)dst.val;
+                               break;
+                       case 4:
+                               *dst.ptr = (u32)dst.val;
+                               break;  /* 64b: zero-ext */
+                       case 8:
+                               *dst.ptr = dst.val;
+                               break;
+                       }
+                       break;
+               case OP_MEM:
+                       if (lock_prefix)
+                               rc = ops->cmpxchg_emulated((unsigned long)dst.
+                                                          ptr, dst.orig_val,
+                                                          dst.val, dst.bytes,
+                                                          ctxt);
+                       else
+                               rc = ops->write_emulated((unsigned long)dst.ptr,
+                                                        dst.val, dst.bytes,
+                                                        ctxt);
+                       if (rc != 0)
+                               goto done;
+               default:
+                       break;
+               }
+       }
+
+       /* Commit shadow register state. */
+       memcpy(ctxt->vcpu->regs, _regs, sizeof _regs);
+       ctxt->eflags = _eflags;
+       ctxt->vcpu->rip = _eip;
+
+done:
+       return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+
+special_insn:
+       if (twobyte)
+               goto twobyte_special_insn;
+       if (rep_prefix) {
+               if (_regs[VCPU_REGS_RCX] == 0) {
+                       ctxt->vcpu->rip = _eip;
+                       goto done;
+               }
+               _regs[VCPU_REGS_RCX]--;
+               _eip = ctxt->vcpu->rip;
+       }
+       switch (b) {
+       case 0xa4 ... 0xa5:     /* movs */
+               dst.type = OP_MEM;
+               dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+               dst.ptr = (unsigned long *)register_address(ctxt->es_base,
+                                                       _regs[VCPU_REGS_RDI]);
+               if ((rc = ops->read_emulated(register_address(
+                     override_base ? *override_base : ctxt->ds_base,
+                     _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0)
+                       goto done;
+               register_address_increment(_regs[VCPU_REGS_RSI],
+                            (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+               register_address_increment(_regs[VCPU_REGS_RDI],
+                            (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+               break;
+       case 0xa6 ... 0xa7:     /* cmps */
+               DPRINTF("Urk! I don't handle CMPS.\n");
+               goto cannot_emulate;
+       case 0xaa ... 0xab:     /* stos */
+               dst.type = OP_MEM;
+               dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+               dst.ptr = (unsigned long *)cr2;
+               dst.val = _regs[VCPU_REGS_RAX];
+               register_address_increment(_regs[VCPU_REGS_RDI],
+                            (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+               break;
+       case 0xac ... 0xad:     /* lods */
+               dst.type = OP_REG;
+               dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+               dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+               if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0)
+                       goto done;
+               register_address_increment(_regs[VCPU_REGS_RSI],
+                          (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+               break;
+       case 0xae ... 0xaf:     /* scas */
+               DPRINTF("Urk! I don't handle SCAS.\n");
+               goto cannot_emulate;
+       }
+       goto writeback;
+
+twobyte_insn:
+       switch (b) {
+       case 0x01: /* lgdt, lidt, lmsw */
+               switch (modrm_reg) {
+                       u16 size;
+                       unsigned long address;
+
+               case 2: /* lgdt */
+                       rc = read_descriptor(ctxt, ops, src.ptr,
+                                            &size, &address, op_bytes);
+                       if (rc)
+                               goto done;
+                       realmode_lgdt(ctxt->vcpu, size, address);
+                       break;
+               case 3: /* lidt */
+                       rc = read_descriptor(ctxt, ops, src.ptr,
+                                            &size, &address, op_bytes);
+                       if (rc)
+                               goto done;
+                       realmode_lidt(ctxt->vcpu, size, address);
+                       break;
+               case 4: /* smsw */
+                       if (modrm_mod != 3)
+                               goto cannot_emulate;
+                       *(u16 *)&_regs[modrm_rm]
+                               = realmode_get_cr(ctxt->vcpu, 0);
+                       break;
+               case 6: /* lmsw */
+                       if (modrm_mod != 3)
+                               goto cannot_emulate;
+                       realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags);
+                       break;
+               case 7: /* invlpg*/
+                       emulate_invlpg(ctxt->vcpu, cr2);
+                       break;
+               default:
+                       goto cannot_emulate;
+               }
+               break;
+       case 0x21: /* mov from dr to reg */
+               if (modrm_mod != 3)
+                       goto cannot_emulate;
+               rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
+               break;
+       case 0x23: /* mov from reg to dr */
+               if (modrm_mod != 3)
+                       goto cannot_emulate;
+               rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
+               break;
+       case 0x40 ... 0x4f:     /* cmov */
+               dst.val = dst.orig_val = src.val;
+               d &= ~Mov;      /* default to no move */
+               /*
+                * First, assume we're decoding an even cmov opcode
+                * (lsb == 0).
+                */
+               switch ((b & 15) >> 1) {
+               case 0: /* cmovo */
+                       d |= (_eflags & EFLG_OF) ? Mov : 0;
+                       break;
+               case 1: /* cmovb/cmovc/cmovnae */
+                       d |= (_eflags & EFLG_CF) ? Mov : 0;
+                       break;
+               case 2: /* cmovz/cmove */
+                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       break;
+               case 3: /* cmovbe/cmovna */
+                       d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+                       break;
+               case 4: /* cmovs */
+                       d |= (_eflags & EFLG_SF) ? Mov : 0;
+                       break;
+               case 5: /* cmovp/cmovpe */
+                       d |= (_eflags & EFLG_PF) ? Mov : 0;
+                       break;
+               case 7: /* cmovle/cmovng */
+                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       /* fall through */
+               case 6: /* cmovl/cmovnge */
+                       d |= (!(_eflags & EFLG_SF) !=
+                             !(_eflags & EFLG_OF)) ? Mov : 0;
+                       break;
+               }
+               /* Odd cmov opcodes (lsb == 1) have inverted sense. */
+               d ^= (b & 1) ? Mov : 0;
+               break;
+       case 0xb0 ... 0xb1:     /* cmpxchg */
+               /*
+                * Save real source value, then compare EAX against
+                * destination.
+                */
+               src.orig_val = src.val;
+               src.val = _regs[VCPU_REGS_RAX];
+               emulate_2op_SrcV("cmp", src, dst, _eflags);
+               /* Always write back. The question is: where to? */
+               d |= Mov;
+               if (_eflags & EFLG_ZF) {
+                       /* Success: write back to memory. */
+                       dst.val = src.orig_val;
+               } else {
+                       /* Failure: write the value we saw to EAX. */
+                       dst.type = OP_REG;
+                       dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+               }
+               break;
+       case 0xa3:
+             bt:               /* bt */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
+               break;
+       case 0xb3:
+             btr:              /* btr */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
+               break;
+       case 0xab:
+             bts:              /* bts */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
+               break;
+       case 0xb6 ... 0xb7:     /* movzx */
+               dst.bytes = op_bytes;
+               dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
+               break;
+       case 0xbb:
+             btc:              /* btc */
+               src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+               emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
+               break;
+       case 0xba:              /* Grp8 */
+               switch (modrm_reg & 3) {
+               case 0:
+                       goto bt;
+               case 1:
+                       goto bts;
+               case 2:
+                       goto btr;
+               case 3:
+                       goto btc;
+               }
+               break;
+       case 0xbe ... 0xbf:     /* movsx */
+               dst.bytes = op_bytes;
+               dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
+               break;
+       }
+       goto writeback;
+
+twobyte_special_insn:
+       /* Disable writeback. */
+       dst.orig_val = dst.val;
+       switch (b) {
+       case 0x0d:              /* GrpP (prefetch) */
+       case 0x18:              /* Grp16 (prefetch/nop) */
+               break;
+       case 0x06:
+               emulate_clts(ctxt->vcpu);
+               break;
+       case 0x20: /* mov cr, reg */
+               if (modrm_mod != 3)
+                       goto cannot_emulate;
+               _regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg);
+               break;
+       case 0x22: /* mov reg, cr */
+               if (modrm_mod != 3)
+                       goto cannot_emulate;
+               realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
+               break;
+       case 0xc7:              /* Grp9 (cmpxchg8b) */
+#if defined(__i386__)
+               {
+                       unsigned long old_lo, old_hi;
+                       if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4,
+                                                     ctxt)) != 0)
+                           || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4,
+                                                        ctxt)) != 0))
+                               goto done;
+                       if ((old_lo != _regs[VCPU_REGS_RAX])
+                           || (old_hi != _regs[VCPU_REGS_RDI])) {
+                               _regs[VCPU_REGS_RAX] = old_lo;
+                               _regs[VCPU_REGS_RDX] = old_hi;
+                               _eflags &= ~EFLG_ZF;
+                       } else if (ops->cmpxchg8b_emulated == NULL) {
+                               rc = X86EMUL_UNHANDLEABLE;
+                               goto done;
+                       } else {
+                               if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo,
+                                                         old_hi,
+                                                         _regs[VCPU_REGS_RBX],
+                                                         _regs[VCPU_REGS_RCX],
+                                                         ctxt)) != 0)
+                                       goto done;
+                               _eflags |= EFLG_ZF;
+                       }
+                       break;
+               }
+#elif defined(__x86_64__)
+               {
+                       unsigned long old, new;
+                       if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
+                               goto done;
+                       if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
+                           ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
+                               _regs[VCPU_REGS_RAX] = (u32) (old >> 0);
+                               _regs[VCPU_REGS_RDX] = (u32) (old >> 32);
+                               _eflags &= ~EFLG_ZF;
+                       } else {
+                               new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX];
+                               if ((rc = ops->cmpxchg_emulated(cr2, old,
+                                                         new, 8, ctxt)) != 0)
+                                       goto done;
+                               _eflags |= EFLG_ZF;
+                       }
+                       break;
+               }
+#endif
+       }
+       goto writeback;
+
+cannot_emulate:
+       DPRINTF("Cannot emulate %02x\n", b);
+       return -1;
+}
+
+#ifdef __XEN__
+
+#include <asm/mm.h>
+#include <asm/uaccess.h>
+
+int
+x86_emulate_read_std(unsigned long addr,
+                    unsigned long *val,
+                    unsigned int bytes, struct x86_emulate_ctxt *ctxt)
+{
+       unsigned int rc;
+
+       *val = 0;
+
+       if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) {
+               propagate_page_fault(addr + bytes - rc, 0);     /* read fault */
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+
+       return X86EMUL_CONTINUE;
+}
+
+int
+x86_emulate_write_std(unsigned long addr,
+                     unsigned long val,
+                     unsigned int bytes, struct x86_emulate_ctxt *ctxt)
+{
+       unsigned int rc;
+
+       if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) {
+               propagate_page_fault(addr + bytes - rc, PGERR_write_access);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
+
+       return X86EMUL_CONTINUE;
+}
+
+#endif
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
new file mode 100644 (file)
index 0000000..658b58d
--- /dev/null
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * x86_emulate.h
+ *
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ *
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
+ */
+
+#ifndef __X86_EMULATE_H__
+#define __X86_EMULATE_H__
+
+struct x86_emulate_ctxt;
+
+/*
+ * x86_emulate_ops:
+ *
+ * These operations represent the instruction emulator's interface to memory.
+ * There are two categories of operation: those that act on ordinary memory
+ * regions (*_std), and those that act on memory regions known to require
+ * special treatment or emulation (*_emulated).
+ *
+ * The emulator assumes that an instruction accesses only one 'emulated memory'
+ * location, that this location is the given linear faulting address (cr2), and
+ * that this is one of the instruction's data operands. Instruction fetches and
+ * stack operations are assumed never to access emulated memory. The emulator
+ * automatically deduces which operand of a string-move operation is accessing
+ * emulated memory, and assumes that the other operand accesses normal memory.
+ *
+ * NOTES:
+ *  1. The emulator isn't very smart about emulated vs. standard memory.
+ *     'Emulated memory' access addresses should be checked for sanity.
+ *     'Normal memory' accesses may fault, and the caller must arrange to
+ *     detect and handle reentrancy into the emulator via recursive faults.
+ *     Accesses may be unaligned and may cross page boundaries.
+ *  2. If the access fails (cannot emulate, or a standard access faults) then
+ *     it is up to the memop to propagate the fault to the guest VM via
+ *     some out-of-band mechanism, unknown to the emulator. The memop signals
+ *     failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ *     then immediately bail.
+ *  3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
+ *     cmpxchg8b_emulated need support 8-byte accesses.
+ *  4. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
+ */
+/* Access completed successfully: continue emulation as normal. */
+#define X86EMUL_CONTINUE        0
+/* Access is unhandleable: bail from emulation and return error to caller. */
+#define X86EMUL_UNHANDLEABLE    1
+/* Terminate emulation but return success to the caller. */
+#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
+#define X86EMUL_RETRY_INSTR     2 /* retry the instruction for some reason */
+#define X86EMUL_CMPXCHG_FAILED  2 /* cmpxchg did not see expected value */
+struct x86_emulate_ops {
+       /*
+        * read_std: Read bytes of standard (non-emulated/special) memory.
+        *           Used for instruction fetch, stack operations, and others.
+        *  @addr:  [IN ] Linear address from which to read.
+        *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+        *  @bytes: [IN ] Number of bytes to read from memory.
+        */
+       int (*read_std)(unsigned long addr,
+                       unsigned long *val,
+                       unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+
+       /*
+        * write_std: Write bytes of standard (non-emulated/special) memory.
+        *            Used for stack operations, and others.
+        *  @addr:  [IN ] Linear address to which to write.
+        *  @val:   [IN ] Value to write to memory (low-order bytes used as
+        *                required).
+        *  @bytes: [IN ] Number of bytes to write to memory.
+        */
+       int (*write_std)(unsigned long addr,
+                        unsigned long val,
+                        unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+
+       /*
+        * read_emulated: Read bytes from emulated/special memory area.
+        *  @addr:  [IN ] Linear address from which to read.
+        *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+        *  @bytes: [IN ] Number of bytes to read from memory.
+        */
+       int (*read_emulated) (unsigned long addr,
+                             unsigned long *val,
+                             unsigned int bytes,
+                             struct x86_emulate_ctxt * ctxt);
+
+       /*
+        * write_emulated: Read bytes from emulated/special memory area.
+        *  @addr:  [IN ] Linear address to which to write.
+        *  @val:   [IN ] Value to write to memory (low-order bytes used as
+        *                required).
+        *  @bytes: [IN ] Number of bytes to write to memory.
+        */
+       int (*write_emulated) (unsigned long addr,
+                              unsigned long val,
+                              unsigned int bytes,
+                              struct x86_emulate_ctxt * ctxt);
+
+       /*
+        * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
+        *                   emulated/special memory area.
+        *  @addr:  [IN ] Linear address to access.
+        *  @old:   [IN ] Value expected to be current at @addr.
+        *  @new:   [IN ] Value to write to @addr.
+        *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
+        */
+       int (*cmpxchg_emulated) (unsigned long addr,
+                                unsigned long old,
+                                unsigned long new,
+                                unsigned int bytes,
+                                struct x86_emulate_ctxt * ctxt);
+
+       /*
+        * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
+        *                     emulated/special memory area.
+        *  @addr:  [IN ] Linear address to access.
+        *  @old:   [IN ] Value expected to be current at @addr.
+        *  @new:   [IN ] Value to write to @addr.
+        * NOTES:
+        *  1. This function is only ever called when emulating a real CMPXCHG8B.
+        *  2. This function is *never* called on x86/64 systems.
+        *  2. Not defining this function (i.e., specifying NULL) is equivalent
+        *     to defining a function that always returns X86EMUL_UNHANDLEABLE.
+        */
+       int (*cmpxchg8b_emulated) (unsigned long addr,
+                                  unsigned long old_lo,
+                                  unsigned long old_hi,
+                                  unsigned long new_lo,
+                                  unsigned long new_hi,
+                                  struct x86_emulate_ctxt * ctxt);
+};
+
+struct cpu_user_regs;
+
+struct x86_emulate_ctxt {
+       /* Register state before/after emulation. */
+       struct kvm_vcpu *vcpu;
+
+       /* Linear faulting address (if emulating a page-faulting instruction). */
+       unsigned long eflags;
+       unsigned long cr2;
+
+       /* Emulated execution mode, represented by an X86EMUL_MODE value. */
+       int mode;
+
+       unsigned long cs_base;
+       unsigned long ds_base;
+       unsigned long es_base;
+       unsigned long ss_base;
+       unsigned long gs_base;
+       unsigned long fs_base;
+};
+
+/* Execution mode, passed to the emulator. */
+#define X86EMUL_MODE_REAL     0        /* Real mode.             */
+#define X86EMUL_MODE_PROT16   2        /* 16-bit protected mode. */
+#define X86EMUL_MODE_PROT32   4        /* 32-bit protected mode. */
+#define X86EMUL_MODE_PROT64   8        /* 64-bit (long) mode.    */
+
+/* Host execution mode. */
+#if defined(__i386__)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
+#elif defined(__x86_64__)
+#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
+#endif
+
+/*
+ * x86_emulate_memop: Emulate an instruction that faulted attempting to
+ *                    read/write a 'special' memory area.
+ * Returns -1 on failure, 0 on success.
+ */
+int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
+                     struct x86_emulate_ops *ops);
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+void *decode_register(u8 modrm_reg, unsigned long *regs,
+                     int highbyte_regs);
+
+#endif                         /* __X86_EMULATE_H__ */
index c92c1521546dfaa7c412f96ff9e021d5369b34ef..4540ade6b6b584385b11d65d337680c59ae96fc1 100644 (file)
@@ -215,6 +215,7 @@ config DM_CRYPT
        tristate "Crypt target support"
        depends on BLK_DEV_DM && EXPERIMENTAL
        select CRYPTO
+       select CRYPTO_CBC
        ---help---
          This device-mapper target allows you to create a device that
          transparently encrypts the data on it. You'll need to activate
index 53bd46dba0cbe69d5da6f1affbcfc008145f0dd9..21e2a7b0884157b8b3016c7a2ac8e74ebfd9fe76 100644 (file)
@@ -3314,6 +3314,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
 
                        module_put(mddev->pers->owner);
                        mddev->pers = NULL;
+
+                       set_capacity(disk, 0);
+                       mddev->changed = 1;
+
                        if (mddev->ro)
                                mddev->ro = 0;
                }
@@ -3333,7 +3337,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
        if (mode == 0) {
                mdk_rdev_t *rdev;
                struct list_head *tmp;
-               struct gendisk *disk;
+
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
                bitmap_destroy(mddev);
@@ -3358,10 +3362,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
 
-               disk = mddev->gendisk;
-               if (disk)
-                       set_capacity(disk, 0);
-               mddev->changed = 1;
        } else if (mddev->pers)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
                        mdname(mddev));
@@ -3371,6 +3371,7 @@ out:
        return err;
 }
 
+#ifndef MODULE
 static void autorun_array(mddev_t *mddev)
 {
        mdk_rdev_t *rdev;
@@ -3485,6 +3486,7 @@ static void autorun_devices(int part)
        }
        printk(KERN_INFO "md: ... autorun DONE.\n");
 }
+#endif /* !MODULE */
 
 static int get_version(void __user * arg)
 {
@@ -3722,6 +3724,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                if (err)
                        export_rdev(rdev);
 
+               md_update_sb(mddev, 1);
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                md_wakeup_thread(mddev->thread);
                return err;
@@ -5273,7 +5276,6 @@ void md_do_sync(mddev_t *mddev)
        mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
 
        if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
-           test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
            !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
            mddev->curr_resync > 2) {
                if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
@@ -5297,6 +5299,7 @@ void md_do_sync(mddev_t *mddev)
                                        rdev->recovery_offset = mddev->curr_resync;
                }
        }
+       set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
  skip:
        mddev->curr_resync = 0;
@@ -5593,7 +5596,7 @@ static void autostart_arrays(int part)
        autorun_devices(part);
 }
 
-#endif
+#endif /* !MODULE */
 
 static __exit void md_exit(void)
 {
index 656fae912fe3550e06a17f14a851f05a7dd63fd2..b3c5e12f081d7482cfa3d204204e40a5e2424cf4 100644 (file)
@@ -1951,6 +1951,7 @@ static int run(mddev_t *mddev)
                    !test_bit(In_sync, &disk->rdev->flags)) {
                        disk->head_position = 0;
                        mddev->degraded++;
+                       conf->fullsync = 1;
                }
        }
        if (mddev->degraded == conf->raid_disks) {
index 52914d5cec76ce1ded14a0fc37a9d2b98b1afe64..377f8bc9b78bea8a54b302716a3572fca3cc7202 100644 (file)
@@ -134,6 +134,8 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
                        if (!test_bit(STRIPE_EXPANDING, &sh->state)) {
                                list_add_tail(&sh->lru, &conf->inactive_list);
                                wake_up(&conf->wait_for_stripe);
+                               if (conf->retry_read_aligned)
+                                       md_wakeup_thread(conf->mddev->thread);
                        }
                }
        }
@@ -542,35 +544,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
        }
 
        if (uptodate) {
-#if 0
-               struct bio *bio;
-               unsigned long flags;
-               spin_lock_irqsave(&conf->device_lock, flags);
-               /* we can return a buffer if we bypassed the cache or
-                * if the top buffer is not in highmem.  If there are
-                * multiple buffers, leave the extra work to
-                * handle_stripe
-                */
-               buffer = sh->bh_read[i];
-               if (buffer &&
-                   (!PageHighMem(buffer->b_page)
-                    || buffer->b_page == bh->b_page )
-                       ) {
-                       sh->bh_read[i] = buffer->b_reqnext;
-                       buffer->b_reqnext = NULL;
-               } else
-                       buffer = NULL;
-               spin_unlock_irqrestore(&conf->device_lock, flags);
-               if (sh->bh_page[i]==bh->b_page)
-                       set_buffer_uptodate(bh);
-               if (buffer) {
-                       if (buffer->b_page != bh->b_page)
-                               memcpy(buffer->b_data, bh->b_data, bh->b_size);
-                       buffer->b_end_io(buffer, 1);
-               }
-#else
                set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif
                if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
                        rdev = conf->disks[i].rdev;
                        printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n",
@@ -616,14 +590,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
                }
        }
        rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
-#if 0
-       /* must restore b_page before unlocking buffer... */
-       if (sh->bh_page[i] != bh->b_page) {
-               bh->b_page = sh->bh_page[i];
-               bh->b_data = page_address(bh->b_page);
-               clear_buffer_uptodate(bh);
-       }
-#endif
        clear_bit(R5_LOCKED, &sh->dev[i].flags);
        set_bit(STRIPE_HANDLE, &sh->state);
        release_stripe(sh);
@@ -821,7 +787,8 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
 static sector_t compute_blocknr(struct stripe_head *sh, int i)
 {
        raid5_conf_t *conf = sh->raid_conf;
-       int raid_disks = sh->disks, data_disks = raid_disks - 1;
+       int raid_disks = sh->disks;
+       int data_disks = raid_disks - conf->max_degraded;
        sector_t new_sector = sh->sector, check;
        int sectors_per_chunk = conf->chunk_size >> 9;
        sector_t stripe;
@@ -857,7 +824,6 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
                }
                break;
        case 6:
-               data_disks = raid_disks - 2;
                if (i == raid6_next_disk(sh->pd_idx, raid_disks))
                        return 0; /* It is the Q disk */
                switch (conf->algorithm) {
@@ -1353,8 +1319,10 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
        int pd_idx, dd_idx;
        int chunk_offset = sector_div(stripe, sectors_per_chunk);
 
-       raid5_compute_sector(stripe*(disks-1)*sectors_per_chunk
-                            + chunk_offset, disks, disks-1, &dd_idx, &pd_idx, conf);
+       raid5_compute_sector(stripe * (disks - conf->max_degraded)
+                            *sectors_per_chunk + chunk_offset,
+                            disks, disks - conf->max_degraded,
+                            &dd_idx, &pd_idx, conf);
        return pd_idx;
 }
 
@@ -1615,15 +1583,6 @@ static void handle_stripe5(struct stripe_head *sh)
                                } else if (test_bit(R5_Insync, &dev->flags)) {
                                        set_bit(R5_LOCKED, &dev->flags);
                                        set_bit(R5_Wantread, &dev->flags);
-#if 0
-                                       /* if I am just reading this block and we don't have
-                                          a failed drive, or any pending writes then sidestep the cache */
-                                       if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
-                                           ! syncing && !failed && !to_write) {
-                                               sh->bh_cache[i]->b_page =  sh->bh_read[i]->b_page;
-                                               sh->bh_cache[i]->b_data =  sh->bh_read[i]->b_data;
-                                       }
-#endif
                                        locked++;
                                        PRINTK("Reading block %d (sync=%d)\n", 
                                                i, syncing);
@@ -1641,9 +1600,6 @@ static void handle_stripe5(struct stripe_head *sh)
                        dev = &sh->dev[i];
                        if ((dev->towrite || i == sh->pd_idx) &&
                            (!test_bit(R5_LOCKED, &dev->flags) 
-#if 0
-|| sh->bh_page[i]!=bh->b_page
-#endif
                                    ) &&
                            !test_bit(R5_UPTODATE, &dev->flags)) {
                                if (test_bit(R5_Insync, &dev->flags)
@@ -1655,9 +1611,6 @@ static void handle_stripe5(struct stripe_head *sh)
                        /* Would I have to read this buffer for reconstruct_write */
                        if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
                            (!test_bit(R5_LOCKED, &dev->flags) 
-#if 0
-|| sh->bh_page[i] != bh->b_page
-#endif
                                    ) &&
                            !test_bit(R5_UPTODATE, &dev->flags)) {
                                if (test_bit(R5_Insync, &dev->flags)) rcw++;
@@ -1865,7 +1818,9 @@ static void handle_stripe5(struct stripe_head *sh)
                return_bi = bi->bi_next;
                bi->bi_next = NULL;
                bi->bi_size = 0;
-               bi->bi_end_io(bi, bytes, 0);
+               bi->bi_end_io(bi, bytes,
+                             test_bit(BIO_UPTODATE, &bi->bi_flags)
+                               ? 0 : -EIO);
        }
        for (i=disks; i-- ;) {
                int rw;
@@ -2193,15 +2148,6 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                                } else if (test_bit(R5_Insync, &dev->flags)) {
                                        set_bit(R5_LOCKED, &dev->flags);
                                        set_bit(R5_Wantread, &dev->flags);
-#if 0
-                                       /* if I am just reading this block and we don't have
-                                          a failed drive, or any pending writes then sidestep the cache */
-                                       if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
-                                           ! syncing && !failed && !to_write) {
-                                               sh->bh_cache[i]->b_page =  sh->bh_read[i]->b_page;
-                                               sh->bh_cache[i]->b_data =  sh->bh_read[i]->b_data;
-                                       }
-#endif
                                        locked++;
                                        PRINTK("Reading block %d (sync=%d)\n",
                                                i, syncing);
@@ -2220,9 +2166,6 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                        if (!test_bit(R5_OVERWRITE, &dev->flags)
                            && i != pd_idx && i != qd_idx
                            && (!test_bit(R5_LOCKED, &dev->flags)
-#if 0
-                               || sh->bh_page[i] != bh->b_page
-#endif
                                    ) &&
                            !test_bit(R5_UPTODATE, &dev->flags)) {
                                if (test_bit(R5_Insync, &dev->flags)) rcw++;
@@ -2418,7 +2361,9 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                return_bi = bi->bi_next;
                bi->bi_next = NULL;
                bi->bi_size = 0;
-               bi->bi_end_io(bi, bytes, 0);
+               bi->bi_end_io(bi, bytes,
+                             test_bit(BIO_UPTODATE, &bi->bi_flags)
+                               ? 0 : -EIO);
        }
        for (i=disks; i-- ;) {
                int rw;
@@ -2611,6 +2556,180 @@ static int raid5_congested(void *data, int bits)
        return 0;
 }
 
+/* We want read requests to align with chunks where possible,
+ * but write requests don't need to.
+ */
+static int raid5_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+{
+       mddev_t *mddev = q->queuedata;
+       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       int max;
+       unsigned int chunk_sectors = mddev->chunk_size >> 9;
+       unsigned int bio_sectors = bio->bi_size >> 9;
+
+       if (bio_data_dir(bio))
+               return biovec->bv_len; /* always allow writes to be mergeable */
+
+       max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+       if (max < 0) max = 0;
+       if (max <= biovec->bv_len && bio_sectors == 0)
+               return biovec->bv_len;
+       else
+               return max;
+}
+
+
+static int in_chunk_boundary(mddev_t *mddev, struct bio *bio)
+{
+       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       unsigned int chunk_sectors = mddev->chunk_size >> 9;
+       unsigned int bio_sectors = bio->bi_size >> 9;
+
+       return  chunk_sectors >=
+               ((sector & (chunk_sectors - 1)) + bio_sectors);
+}
+
+/*
+ *  add bio to the retry LIFO  ( in O(1) ... we are in interrupt )
+ *  later sampled by raid5d.
+ */
+static void add_bio_to_retry(struct bio *bi,raid5_conf_t *conf)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&conf->device_lock, flags);
+
+       bi->bi_next = conf->retry_read_aligned_list;
+       conf->retry_read_aligned_list = bi;
+
+       spin_unlock_irqrestore(&conf->device_lock, flags);
+       md_wakeup_thread(conf->mddev->thread);
+}
+
+
+static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
+{
+       struct bio *bi;
+
+       bi = conf->retry_read_aligned;
+       if (bi) {
+               conf->retry_read_aligned = NULL;
+               return bi;
+       }
+       bi = conf->retry_read_aligned_list;
+       if(bi) {
+               conf->retry_read_aligned = bi->bi_next;
+               bi->bi_next = NULL;
+               bi->bi_phys_segments = 1; /* biased count of active stripes */
+               bi->bi_hw_segments = 0; /* count of processed stripes */
+       }
+
+       return bi;
+}
+
+
+/*
+ *  The "raid5_align_endio" should check if the read succeeded and if it
+ *  did, call bio_endio on the original bio (having bio_put the new bio
+ *  first).
+ *  If the read failed..
+ */
+static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
+{
+       struct bio* raid_bi  = bi->bi_private;
+       mddev_t *mddev;
+       raid5_conf_t *conf;
+       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+       mdk_rdev_t *rdev;
+
+       if (bi->bi_size)
+               return 1;
+       bio_put(bi);
+
+       mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata;
+       conf = mddev_to_conf(mddev);
+       rdev = (void*)raid_bi->bi_next;
+       raid_bi->bi_next = NULL;
+
+       rdev_dec_pending(rdev, conf->mddev);
+
+       if (!error && uptodate) {
+               bio_endio(raid_bi, bytes, 0);
+               if (atomic_dec_and_test(&conf->active_aligned_reads))
+                       wake_up(&conf->wait_for_stripe);
+               return 0;
+       }
+
+
+       PRINTK("raid5_align_endio : io error...handing IO for a retry\n");
+
+       add_bio_to_retry(raid_bi, conf);
+       return 0;
+}
+
+static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
+{
+       mddev_t *mddev = q->queuedata;
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+       const unsigned int raid_disks = conf->raid_disks;
+       const unsigned int data_disks = raid_disks - conf->max_degraded;
+       unsigned int dd_idx, pd_idx;
+       struct bio* align_bi;
+       mdk_rdev_t *rdev;
+
+       if (!in_chunk_boundary(mddev, raid_bio)) {
+               printk("chunk_aligned_read : non aligned\n");
+               return 0;
+       }
+       /*
+        * use bio_clone to make a copy of the bio
+        */
+       align_bi = bio_clone(raid_bio, GFP_NOIO);
+       if (!align_bi)
+               return 0;
+       /*
+        *   set bi_end_io to a new function, and set bi_private to the
+        *     original bio.
+        */
+       align_bi->bi_end_io  = raid5_align_endio;
+       align_bi->bi_private = raid_bio;
+       /*
+        *      compute position
+        */
+       align_bi->bi_sector =  raid5_compute_sector(raid_bio->bi_sector,
+                                       raid_disks,
+                                       data_disks,
+                                       &dd_idx,
+                                       &pd_idx,
+                                       conf);
+
+       rcu_read_lock();
+       rdev = rcu_dereference(conf->disks[dd_idx].rdev);
+       if (rdev && test_bit(In_sync, &rdev->flags)) {
+               atomic_inc(&rdev->nr_pending);
+               rcu_read_unlock();
+               raid_bio->bi_next = (void*)rdev;
+               align_bi->bi_bdev =  rdev->bdev;
+               align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+               align_bi->bi_sector += rdev->data_offset;
+
+               spin_lock_irq(&conf->device_lock);
+               wait_event_lock_irq(conf->wait_for_stripe,
+                                   conf->quiesce == 0,
+                                   conf->device_lock, /* nothing */);
+               atomic_inc(&conf->active_aligned_reads);
+               spin_unlock_irq(&conf->device_lock);
+
+               generic_make_request(align_bi);
+               return 1;
+       } else {
+               rcu_read_unlock();
+               bio_put(align_bi);
+               return 0;
+       }
+}
+
+
 static int make_request(request_queue_t *q, struct bio * bi)
 {
        mddev_t *mddev = q->queuedata;
@@ -2632,6 +2751,11 @@ static int make_request(request_queue_t *q, struct bio * bi)
        disk_stat_inc(mddev->gendisk, ios[rw]);
        disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
 
+       if (bio_data_dir(bi) == READ &&
+            mddev->reshape_position == MaxSector &&
+            chunk_aligned_read(q,bi))
+               return 0;
+
        logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
        last_sector = bi->bi_sector + (bi->bi_size>>9);
        bi->bi_next = NULL;
@@ -2739,7 +2863,9 @@ static int make_request(request_queue_t *q, struct bio * bi)
                if ( rw == WRITE )
                        md_write_end(mddev);
                bi->bi_size = 0;
-               bi->bi_end_io(bi, bytes, 0);
+               bi->bi_end_io(bi, bytes,
+                             test_bit(BIO_UPTODATE, &bi->bi_flags)
+                               ? 0 : -EIO);
        }
        return 0;
 }
@@ -2950,6 +3076,74 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        return STRIPE_SECTORS;
 }
 
+static int  retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
+{
+       /* We may not be able to submit a whole bio at once as there
+        * may not be enough stripe_heads available.
+        * We cannot pre-allocate enough stripe_heads as we may need
+        * more than exist in the cache (if we allow ever large chunks).
+        * So we do one stripe head at a time and record in
+        * ->bi_hw_segments how many have been done.
+        *
+        * We *know* that this entire raid_bio is in one chunk, so
+        * it will be only one 'dd_idx' and only need one call to raid5_compute_sector.
+        */
+       struct stripe_head *sh;
+       int dd_idx, pd_idx;
+       sector_t sector, logical_sector, last_sector;
+       int scnt = 0;
+       int remaining;
+       int handled = 0;
+
+       logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+       sector = raid5_compute_sector(  logical_sector,
+                                       conf->raid_disks,
+                                       conf->raid_disks - conf->max_degraded,
+                                       &dd_idx,
+                                       &pd_idx,
+                                       conf);
+       last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
+
+       for (; logical_sector < last_sector;
+            logical_sector += STRIPE_SECTORS, scnt++) {
+
+               if (scnt < raid_bio->bi_hw_segments)
+                       /* already done this stripe */
+                       continue;
+
+               sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1);
+
+               if (!sh) {
+                       /* failed to get a stripe - must wait */
+                       raid_bio->bi_hw_segments = scnt;
+                       conf->retry_read_aligned = raid_bio;
+                       return handled;
+               }
+
+               set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
+               add_stripe_bio(sh, raid_bio, dd_idx, 0);
+               handle_stripe(sh, NULL);
+               release_stripe(sh);
+               handled++;
+       }
+       spin_lock_irq(&conf->device_lock);
+       remaining = --raid_bio->bi_phys_segments;
+       spin_unlock_irq(&conf->device_lock);
+       if (remaining == 0) {
+               int bytes = raid_bio->bi_size;
+
+               raid_bio->bi_size = 0;
+               raid_bio->bi_end_io(raid_bio, bytes,
+                             test_bit(BIO_UPTODATE, &raid_bio->bi_flags)
+                               ? 0 : -EIO);
+       }
+       if (atomic_dec_and_test(&conf->active_aligned_reads))
+               wake_up(&conf->wait_for_stripe);
+       return handled;
+}
+
+
+
 /*
  * This is our raid5 kernel thread.
  *
@@ -2971,6 +3165,7 @@ static void raid5d (mddev_t *mddev)
        spin_lock_irq(&conf->device_lock);
        while (1) {
                struct list_head *first;
+               struct bio *bio;
 
                if (conf->seq_flush != conf->seq_write) {
                        int seq = conf->seq_flush;
@@ -2987,6 +3182,16 @@ static void raid5d (mddev_t *mddev)
                    !list_empty(&conf->delayed_list))
                        raid5_activate_delayed(conf);
 
+               while ((bio = remove_bio_from_retry(conf))) {
+                       int ok;
+                       spin_unlock_irq(&conf->device_lock);
+                       ok = retry_aligned_read(conf, bio);
+                       spin_lock_irq(&conf->device_lock);
+                       if (!ok)
+                               break;
+                       handled++;
+               }
+
                if (list_empty(&conf->handle_list))
                        break;
 
@@ -3174,6 +3379,7 @@ static int run(mddev_t *mddev)
        INIT_LIST_HEAD(&conf->inactive_list);
        atomic_set(&conf->active_stripes, 0);
        atomic_set(&conf->preread_active_stripes, 0);
+       atomic_set(&conf->active_aligned_reads, 0);
 
        PRINTK("raid5: run(%s) called.\n", mdname(mddev));
 
@@ -3320,6 +3526,8 @@ static int run(mddev_t *mddev)
        mddev->array_size =  mddev->size * (conf->previous_raid_disks -
                                            conf->max_degraded);
 
+       blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
+
        return 0;
 abort:
        if (conf) {
@@ -3694,7 +3902,8 @@ static void raid5_quiesce(mddev_t *mddev, int state)
                spin_lock_irq(&conf->device_lock);
                conf->quiesce = 1;
                wait_event_lock_irq(conf->wait_for_stripe,
-                                   atomic_read(&conf->active_stripes) == 0,
+                                   atomic_read(&conf->active_stripes) == 0 &&
+                                   atomic_read(&conf->active_aligned_reads) == 0,
                                    conf->device_lock, /* nothing */);
                spin_unlock_irq(&conf->device_lock);
                break;
index 9f7e1fe8c97e254ee107bbf771550223d6219557..87410dbd3df41829d36bd49e37af91272718eef5 100644 (file)
@@ -67,6 +67,7 @@ source "drivers/media/common/Kconfig"
 
 config VIDEO_TUNER
        tristate
+       depends on I2C
 
 config VIDEO_BUF
        tristate
@@ -82,6 +83,7 @@ config VIDEO_IR
 
 config VIDEO_TVEEPROM
        tristate
+       depends on I2C
 
 config USB_DABUSB
        tristate "DABUSB driver"
index db753443587acf5a2cf7deddbeafebcb4974f18d..f51e02fe3655c2942777ebc6dc114c1ffc47d79e 100644 (file)
@@ -1552,3 +1552,58 @@ IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_norwood);
+
+/* From reading the following remotes:
+ * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
+ * Hauppauge (from NOVA-CI-s box product)
+ * This is a "middle of the road" approach, differences are noted
+ */
+IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+       [ 0x0a ] = KEY_ENTER,
+       [ 0x0b ] = KEY_RED,
+       [ 0x0c ] = KEY_POWER,             /* RADIO on Hauppauge */
+       [ 0x0d ] = KEY_MUTE,
+       [ 0x0f ] = KEY_A,                 /* TV on Hauppauge */
+       [ 0x10 ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_VOLUMEDOWN,
+       [ 0x14 ] = KEY_B,
+       [ 0x1c ] = KEY_UP,
+       [ 0x1d ] = KEY_DOWN,
+       [ 0x1e ] = KEY_OPTION,            /* RESERVED on Hauppauge */
+       [ 0x1f ] = KEY_BREAK,
+       [ 0x20 ] = KEY_CHANNELUP,
+       [ 0x21 ] = KEY_CHANNELDOWN,
+       [ 0x22 ] = KEY_PREVIOUS,          /* Prev. Ch on Zenith, SOURCE on Hauppauge */
+       [ 0x24 ] = KEY_RESTART,
+       [ 0x25 ] = KEY_OK,
+       [ 0x26 ] = KEY_CYCLEWINDOWS,      /* MINIMIZE on Hauppauge */
+       [ 0x28 ] = KEY_ENTER,             /* VCR mode on Zenith */
+       [ 0x29 ] = KEY_PAUSE,
+       [ 0x2b ] = KEY_RIGHT,
+       [ 0x2c ] = KEY_LEFT,
+       [ 0x2e ] = KEY_MENU,              /* FULL SCREEN on Hauppauge */
+       [ 0x30 ] = KEY_SLOW,
+       [ 0x31 ] = KEY_PREVIOUS,          /* VCR mode on Zenith */
+       [ 0x32 ] = KEY_REWIND,
+       [ 0x34 ] = KEY_FASTFORWARD,
+       [ 0x35 ] = KEY_PLAY,
+       [ 0x36 ] = KEY_STOP,
+       [ 0x37 ] = KEY_RECORD,
+       [ 0x38 ] = KEY_TUNER,             /* TV/VCR on Zenith */
+       [ 0x3a ] = KEY_C,
+       [ 0x3c ] = KEY_EXIT,
+       [ 0x3d ] = KEY_POWER2,
+       [ 0x3e ] = KEY_TUNER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
index 5297a365c928e2b8c8928c8f3edafc7324db1915..8c85efc26527fe9bf5bdd85473f014b568871876 100644 (file)
@@ -189,13 +189,21 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
                saa7146_write(dev, I2C_TRANSFER, *dword);
 
                dev->i2c_op = 1;
+               SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
                SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
                saa7146_write(dev, MC2, (MASK_00 | MASK_16));
 
-               wait_event_interruptible(dev->i2c_wq, dev->i2c_op == 0);
-               if (signal_pending (current)) {
-                       /* a signal arrived */
-                       return -ERESTARTSYS;
+               timeout = HZ/100 + 1; /* 10ms */
+               timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
+               if (timeout == -ERESTARTSYS || dev->i2c_op) {
+                       SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+                       SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
+                       if (timeout == -ERESTARTSYS)
+                               /* a signal arrived */
+                               return -ERESTARTSYS;
+
+                       printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+                       return -EIO;
                }
                status = saa7146_read(dev, I2C_STATUS);
        } else {
index a0dcd59da76e5833502814abf62d66eda780ae79..79875958930e1ba4a53d18ee5f0b94b52cb03f59 100644 (file)
@@ -9,6 +9,7 @@ config DVB_B2C2_FLEXCOP
        select DVB_STV0297 if !DVB_FE_CUSTOMISE
        select DVB_BCM3510 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
        help
          Support for the digital TV receiver chip made by B2C2 Inc. included in
          Technisats PCI cards and USB boxes.
index b8ba8786345783e107aa6e7a31babc4ff0cd6bd4..c2b35e3662422bc380a47d064dc3da4ce8c6d137 100644 (file)
@@ -14,7 +14,7 @@
 #include "stv0297.h"
 #include "mt312.h"
 #include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
 #include "dvb-pll.h"
 
 /* lnb control */
@@ -303,12 +303,6 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
        return request_firmware(fw, name, fc->dev);
 }
 
-static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
-{
-       struct flexcop_device *fc = fe->dvb->priv;
-       return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
-}
-
 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
        .demod_address       = 0x59,
        .demod_chip          = LGDT3303,
@@ -533,7 +527,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
        /* try the air atsc 3nd generation (lgdt3303) */
        if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC3;
-               fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+               dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap);
                info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
        } else
        /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
index ae2ff5dc238d958d03f92fe9bf2a2c4d3926e93d..dd66b60fbc98439021bd29bf8eed68ae5c440ffc 100644 (file)
@@ -1,13 +1,13 @@
 config DVB_BT8XX
        tristate "BT8xx based PCI cards"
        depends on DVB_CORE && PCI && I2C && VIDEO_BT848
-       select DVB_PLL
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_SP887X if !DVB_FE_CUSTOMISE
        select DVB_NXT6000 if !DVB_FE_CUSTOMISE
        select DVB_CX24110 if !DVB_FE_CUSTOMISE
        select DVB_OR51211 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select FW_LOADER
        help
index 14e69a736edae5f50bf3207b9c1b0a205199faff..80a85cb4975fb6d28e95f9a9cefc0d1223dc2140 100644 (file)
@@ -34,7 +34,6 @@
 #include "dvb_frontend.h"
 #include "dvb-bt8xx.h"
 #include "bt878.h"
-#include "dvb-pll.h"
 
 static int debug;
 
@@ -568,12 +567,6 @@ static struct mt352_config digitv_alps_tded4_config = {
        .demod_init = digitv_alps_tded4_demod_init,
 };
 
-static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
-       struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
-       return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
-}
-
 static struct lgdt330x_config tdvs_tua6034_config = {
        .demod_address    = 0x0e,
        .demod_chip       = LGDT3303,
@@ -616,7 +609,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                lgdt330x_reset(card);
                card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
                if (card->fe != NULL) {
-                       card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
+                       dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter);
                        dprintk ("dvb_bt8xx: lgdt330x detected\n");
                }
                break;
index 4745a9017a1993476f82e2fae5f6ef049ed5910c..e75f4173c0592201b743dd79f1be62d83c1a308f 100644 (file)
@@ -37,7 +37,7 @@
 #include "cx24110.h"
 #include "or51211.h"
 #include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
 #include "zl10353.h"
 
 struct dvb_bt8xx_card {
index 9123147e376f56c930c02b74e9bbb4d449b4090a..d64b96cb0c469ea9e325eca7e557e0f084ce7c39 100644 (file)
@@ -746,6 +746,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
                                dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
                                input_report_key(cinergyt2->rc_input_dev,
                                                 cinergyt2->rc_input_event, 0);
+                               input_sync(cinergyt2->rc_input_dev);
                                cinergyt2->rc_input_event = KEY_MAX;
                        }
                        cinergyt2->rc_last_code = ~0;
@@ -783,6 +784,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
                        dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
                        input_report_key(cinergyt2->rc_input_dev,
                                         cinergyt2->rc_input_event, 1);
+                       input_sync(cinergyt2->rc_input_dev);
                        cinergyt2->rc_last_code = rc_events[n].value;
                }
        }
@@ -798,8 +800,9 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
 {
        struct input_dev *input_dev;
        int i;
+       int err;
 
-       cinergyt2->rc_input_dev = input_dev = input_allocate_device();
+       input_dev = input_allocate_device();
        if (!input_dev)
                return -ENOMEM;
 
@@ -817,7 +820,13 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
        input_dev->keycodesize = 0;
        input_dev->keycodemax = 0;
 
-       input_register_device(cinergyt2->rc_input_dev);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+
+       cinergyt2->rc_input_dev = input_dev;
        schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
 
        return 0;
index a263b3f3c21d777c6549044289d4bef0a3d1eb25..ad52143602cd4ce2f8924b251ea34b2babec512a 100644 (file)
@@ -69,6 +69,8 @@ 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_TUNER_MT2060 if !DVB_FE_CUSTOMISE
        help
@@ -96,6 +98,7 @@ config DVB_USB_CXUSB
        depends on DVB_USB
        select DVB_CX22702 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        help
@@ -157,6 +160,17 @@ config DVB_USB_NOVA_T_USB2
        help
          Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
+config DVB_USB_TTUSB2
+       tristate "Pinnacle 400e DVB-S USB2.0 support"
+       depends on DVB_USB
+       select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_TDA826X if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
+         firmware protocol used by this module is similar to the one used by the
+         old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko.
+
 config DVB_USB_DTT200U
        tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
        depends on DVB_USB
index e239107998e58d7b236ff90a3d75bdbf4b82fb44..154d593bbb02788a5c9a9589dab63fc54bfa7546 100644 (file)
@@ -36,6 +36,9 @@ obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
 dvb-usb-cxusb-objs = cxusb.o
 obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
 
+dvb-usb-ttusb2-objs = ttusb2.o
+obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
+
 dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
 obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
 
index 2ed3eb62d787c49d8cde32491f6e27dbf53a6e14..a6c5f19f680d6dd38452a0f5356885bfa082994b 100644 (file)
@@ -116,24 +116,24 @@ static struct dvb_usb_device_properties a800_properties = {
                {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-
-       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
-       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
-
-       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+
+                       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+                       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                                       .stream = {
+                                               .type = USB_BULK,
+                               .count = 7,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
 
                        .size_of_priv     = sizeof(struct dibusb_state),
                },
index 43f39069ef34551eadbf746ba3da2bf5e9291db3..15d12fce34df871e8ffaed1b4c39b7566fa97d82 100644 (file)
  * TODO: Use the cx25840-driver for the analogue part
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
- * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net)
+ * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
  * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
  *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the Free
- *     Software Foundation, version 2.
+ *   This program is 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.
  *
  * see Documentation/dvb/README.dvb-usb for more information
  */
 
 #include "cx22702.h"
 #include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
-module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
+module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
-               u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+                         u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
        int wo = (rbuf == NULL || rlen == 0); /* write-only */
        u8 sndbuf[1+wlen];
-       memset(sndbuf,0,1+wlen);
+       memset(sndbuf, 0, 1+wlen);
 
        sndbuf[0] = cmd;
-       memcpy(&sndbuf[1],wbuf,wlen);
+       memcpy(&sndbuf[1], wbuf, wlen);
        if (wo)
-               dvb_usb_generic_write(d,sndbuf,1+wlen);
+               dvb_usb_generic_write(d, sndbuf, 1+wlen);
        else
-               dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
+               dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
 
        return 0;
 }
@@ -58,14 +58,14 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
 {
        struct cxusb_state *st = d->priv;
-       u8 o[2],i;
+       u8 o[2], i;
 
        if (st->gpio_write_state[GPIO_TUNER] == onoff)
                return;
 
        o[0] = GPIO_TUNER;
        o[1] = onoff;
-       cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1);
+       cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
 
        if (i != 0x01)
                deb_info("gpio_write failed.\n");
@@ -74,7 +74,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
 }
 
 /* I2C */
-static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                         int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
@@ -89,12 +90,12 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
 
                if (d->udev->descriptor.idVendor == USB_VID_MEDION)
                        switch (msg[i].addr) {
-                               case 0x63:
-                                       cxusb_gpio_tuner(d,0);
-                                       break;
-                               default:
-                                       cxusb_gpio_tuner(d,1);
-                                       break;
+                       case 0x63:
+                               cxusb_gpio_tuner(d, 0);
+                               break;
+                       default:
+                               cxusb_gpio_tuner(d, 1);
+                               break;
                        }
 
                /* read request */
@@ -103,26 +104,27 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
                        obuf[0] = msg[i].len;
                        obuf[1] = msg[i+1].len;
                        obuf[2] = msg[i].addr;
-                       memcpy(&obuf[3],msg[i].buf,msg[i].len);
+                       memcpy(&obuf[3], msg[i].buf, msg[i].len);
 
                        if (cxusb_ctrl_msg(d, CMD_I2C_READ,
-                                               obuf, 3+msg[i].len,
-                                               ibuf, 1+msg[i+1].len) < 0)
+                                          obuf, 3+msg[i].len,
+                                          ibuf, 1+msg[i+1].len) < 0)
                                break;
 
                        if (ibuf[0] != 0x08)
                                deb_i2c("i2c read may have failed\n");
 
-                       memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
+                       memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
 
                        i++;
                } else { /* write */
                        u8 obuf[2+msg[i].len], ibuf;
                        obuf[0] = msg[i].addr;
                        obuf[1] = msg[i].len;
-                       memcpy(&obuf[2],msg[i].buf,msg[i].len);
+                       memcpy(&obuf[2], msg[i].buf, msg[i].len);
 
-                       if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
+                       if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
+                                          2+msg[i].len, &ibuf,1) < 0)
                                break;
                        if (ibuf != 0x08)
                                deb_i2c("i2c write may have failed\n");
@@ -324,16 +326,8 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
-                                         struct dvb_frontend_parameters *fep)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       return lg_h06xf_pll_set(fe, &adap->dev->i2c_adap, fep);
-}
-
 static struct cx22702_config cxusb_cx22702_config = {
        .demod_address = 0x63,
-
        .output_mode = CX22702_PARALLEL_OUTPUT,
 };
 
@@ -374,31 +368,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 
 static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_thomson_dtt7579;
-       adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+                  NULL, &dvb_pll_thomson_dtt7579);
        return 0;
 }
 
 static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x61;
-       adap->pll_desc = &dvb_pll_lg_z201;
-       adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
        return 0;
 }
 
 static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->pll_addr = 0x60;
-       adap->pll_desc = &dvb_pll_thomson_dtt7579;
-       adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+                  NULL, &dvb_pll_thomson_dtt7579);
        return 0;
 }
 
-static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_adapter *adap)
+static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
+       dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap);
        return 0;
 }
 
@@ -410,7 +400,8 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
 
-       if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL)
+       if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
+                                  &adap->dev->i2c_adap)) != NULL)
                return 0;
 
        return -EIO;
@@ -423,7 +414,8 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL)
+       if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config,
+                                  &adap->dev->i2c_adap)) != NULL)
                return 0;
 
        return -EIO;
@@ -437,7 +429,8 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL)
+       if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
+                                  &adap->dev->i2c_adap)) != NULL)
                return 0;
 
        return -EIO;
@@ -450,8 +443,11 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
 
        cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
 
-       if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) ||
-               ((adap->fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL))
+       if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
+                                   &adap->dev->i2c_adap)) != NULL) ||
+               ((adap->fe = dvb_attach(zl10353_attach,
+                                       &cxusb_zl10353_dee1601_config,
+                                       &adap->dev->i2c_adap)) != NULL))
                return 0;
 
        return -EIO;
@@ -463,7 +459,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
  */
 
 #define BLUEBIRD_01_ID_OFFSET 6638
-static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw)
+static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
+                                                 const struct firmware *fw)
 {
        if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
                return -EINVAL;
@@ -471,10 +468,12 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const
        if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
            fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
 
-               fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1;
-               fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8;
+               fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
+                       udev->descriptor.idProduct + 1;
+               fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
+                       udev->descriptor.idProduct >> 8;
 
-               return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2);
+               return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
        }
 
        return -EINVAL;
@@ -488,7 +487,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
-               const struct usb_device_id *id)
+                      const struct usb_device_id *id)
 {
        if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
                dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
@@ -502,20 +501,20 @@ static int cxusb_probe(struct usb_interface *intf,
 }
 
 static struct usb_device_id cxusb_table [] = {
-               { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
-               { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
-               {}              /* Terminating entry */
+       { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
+       { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+       {}              /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
 
@@ -529,20 +528,20 @@ static struct dvb_usb_device_properties cxusb_medion_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = cxusb_streaming_ctrl,
-       .frontend_attach  = cxusb_cx22702_frontend_attach,
-       .tuner_attach     = cxusb_fmd1216me_tuner_attach,
-       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-               .count = 5,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_cx22702_frontend_attach,
+                       .tuner_attach     = cxusb_fmd1216me_tuner_attach,
+                       /* parameter for the MPEG2-data transfer */
+                                       .stream = {
+                                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
 
                },
        },
@@ -575,21 +574,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = cxusb_streaming_ctrl,
-       .frontend_attach  = cxusb_lgdt3303_frontend_attach,
-       .tuner_attach     = cxusb_lgdt3303_tuner_attach,
-
-       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-               .count = 5,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_lgdt3303_frontend_attach,
+                       .tuner_attach     = cxusb_lgh064f_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                                       .stream = {
+                                               .type = USB_BULK,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
                },
        },
 
@@ -627,20 +626,20 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = cxusb_streaming_ctrl,
-       .frontend_attach  = cxusb_dee1601_frontend_attach,
-       .tuner_attach     = cxusb_dee1601_tuner_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_dee1601_frontend_attach,
+                       .tuner_attach     = cxusb_dee1601_tuner_attach,
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 5,
-               .endpoint = 0x04,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                               .count = 5,
+                               .endpoint = 0x04,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
                },
        },
 
@@ -686,21 +685,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
        .num_adapters = 2,
        .adapter = {
                {
-       .streaming_ctrl   = cxusb_streaming_ctrl,
-       .frontend_attach  = cxusb_mt352_frontend_attach,
-       .tuner_attach     = cxusb_lgz201_tuner_attach,
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_mt352_frontend_attach,
+                       .tuner_attach     = cxusb_lgz201_tuner_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 5,
-               .endpoint = 0x04,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                               .count = 5,
+                               .endpoint = 0x04,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
                },
        },
        .power_ctrl       = cxusb_bluebird_power_ctrl,
@@ -736,21 +735,21 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = cxusb_streaming_ctrl,
-       .frontend_attach  = cxusb_mt352_frontend_attach,
-       .tuner_attach     = cxusb_dtt7579_tuner_attach,
+                       .streaming_ctrl   = cxusb_streaming_ctrl,
+                       .frontend_attach  = cxusb_mt352_frontend_attach,
+                       .tuner_attach     = cxusb_dtt7579_tuner_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 5,
-               .endpoint = 0x04,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                               .count = 5,
+                               .endpoint = 0x04,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
                },
        },
        .power_ctrl       = cxusb_bluebird_power_ctrl,
@@ -776,7 +775,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
 static struct usb_driver cxusb_driver = {
        .name           = "dvb_usb_cxusb",
        .probe          = cxusb_probe,
-       .disconnect = dvb_usb_device_exit,
+       .disconnect     = dvb_usb_device_exit,
        .id_table       = cxusb_table,
 };
 
@@ -802,7 +801,7 @@ module_init (cxusb_module_init);
 module_exit (cxusb_module_exit);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_AUTHOR("Michael Krufky <mkrufky@m1k.net>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
 MODULE_VERSION("1.0-alpha");
index ac84347f9d4c2b6d896cf5968dcf8ab15c8c6132..cda3adea24fb2fdf121cbc3053f7aaaf1f720a63 100644 (file)
@@ -24,18 +24,23 @@ extern int dvb_usb_dib0700_debug;
 #define REQUEST_I2C_WRITE    0x3
 #define REQUEST_POLL_RC      0x4
 #define REQUEST_JUMPRAM      0x8
+#define REQUEST_SET_CLOCK    0xB
 #define REQUEST_SET_GPIO     0xC
 #define REQUEST_ENABLE_VIDEO 0xF
        // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
        // 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
        // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
+#define REQUEST_GET_VERSION  0x15
 
 struct dib0700_state {
        u8 channel_state;
        u16 mt2060_if1[2];
+
+       u8 is_dib7000pc;
 };
 
 extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
+extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
 extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
 extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 extern struct i2c_algorithm dib0700_i2c_algo;
index dca6c6985661ec2755ba154b0a3f76fb51eec1d5..6a4d150784a6e776cfe4fbe946c0f004dc47700d 100644 (file)
@@ -135,14 +135,46 @@ struct i2c_algorithm dib0700_i2c_algo = {
 int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
                        struct dvb_usb_device_description **desc, int *cold)
 {
-       u8 buf[3] = { REQUEST_SET_GPIO, 4, (GPIO_IN << 7) | (0 << 6) }; // GPIO4 is save - used for I2C
-       *cold = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
-               buf[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, buf, 3, USB_CTRL_GET_TIMEOUT) != 3;
+       u8 b[16];
+       s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
+               REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
+
+       deb_info("FW GET_VERSION length: %d\n",ret);
+
+       *cold = ret <= 0;
 
        deb_info("cold: %d\n", *cold);
        return 0;
 }
 
+static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+       u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
+       u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+{
+       u8 b[10];
+       b[0] = REQUEST_SET_CLOCK;
+       b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
+       b[2] = (pll_prediv >> 8)  & 0xff; // MSB
+       b[3] =  pll_prediv        & 0xff; // LSB
+       b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
+       b[5] =  pll_loopdiv       & 0xff; // LSB
+       b[6] = (free_div >> 8)    & 0xff; // MSB
+       b[7] =  free_div          & 0xff; // LSB
+       b[8] = (dsuScaler >> 8)   & 0xff; // MSB
+       b[9] =  dsuScaler         & 0xff; // LSB
+
+       return dib0700_ctrl_wr(d, b, 10);
+}
+
+int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
+{
+       switch (clk_MHz) {
+               case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
+               default: return -EINVAL;
+       }
+       return 0;
+}
+
 static int dib0700_jumpram(struct usb_device *udev, u32 address)
 {
        int ret, actlen;
@@ -197,7 +229,7 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
                /* start the firmware */
                if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
                        info("firmware started successfully.");
-                       msleep(100);
+                       msleep(500);
                }
        } else
                ret = -EIO;
index e473bfed226b6004e55b4bb158bf7cc6f58558a7..2208757d90173e55aafe001f7f3e1c57dae610c4 100644 (file)
@@ -9,6 +9,8 @@
 #include "dib0700.h"
 
 #include "dib3000mc.h"
+#include "dib7000m.h"
+#include "dib7000p.h"
 #include "mt2060.h"
 
 static int force_lna_activation;
@@ -95,37 +97,189 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 }
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
-/*
-static struct mt2060_config stk7000p_mt2060_config = {
-       0x60
+static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
+       BAND_UHF | BAND_VHF,       // band_caps
+
+       /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+        * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+       712,  // inv_gain
+       41,  // time_stabiliz
+
+       0,  // alpha_level
+       118,  // thlock
+
+       0,     // wbd_inv
+       4095,  // wbd_ref
+       0,     // wbd_sel
+       0,     // wbd_alpha
+
+       42598,  // agc1_max
+       17694,  // agc1_min
+       45875,  // agc2_max
+       2621,  // agc2_min
+       0,  // agc1_pt1
+       76,  // agc1_pt2
+       139,  // agc1_pt3
+       52,  // agc1_slope1
+       59,  // agc1_slope2
+       107,  // agc2_pt1
+       172,  // agc2_pt2
+       57,  // agc2_slope1
+       70,  // agc2_slope2
+
+       21,  // alpha_mant
+       25,  // alpha_exp
+       28,  // beta_mant
+       48,  // beta_exp
+
+       1,  // perform_agc_softsplit
+       {  0,     // split_min
+          107,   // split_max
+          51800, // global_split_min
+          24700  // global_split_max
+       },
+};
+
+static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
+       BAND_UHF | BAND_VHF,
+
+       /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+        * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+       (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+       712, // inv_gain
+       41,  // time_stabiliz
+
+       0,   // alpha_level
+       118, // thlock
+
+       0,    // wbd_inv
+       4095, // wbd_ref
+       0,    // wbd_sel
+       0,    // wbd_alpha
+
+       42598, // agc1_max
+       16384, // agc1_min
+       42598, // agc2_max
+           0, // agc2_min
+
+         0,   // agc1_pt1
+       137,   // agc1_pt2
+       255,   // agc1_pt3
+
+         0,   // agc1_slope1
+       255,   // agc1_slope2
+
+       0,     // agc2_pt1
+       0,     // agc2_pt2
+
+        0,    // agc2_slope1
+       41,    // agc2_slope2
+
+       15, // alpha_mant
+       25, // alpha_exp
+
+       28, // beta_mant
+       48, // beta_exp
+
+       0, // perform_agc_softsplit
+};
+
+static struct dibx000_bandwidth_config stk7700p_pll_config = {
+       60000, 30000, // internal, sampling
+       1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+       0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+       (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+       60258167, // ifreq
+       20452225, // timf
+};
+
+static struct dib7000m_config stk7700p_dib7000m_config = {
+       .dvbt_mode = 1,
+       .output_mpeg2_in_188_bytes = 1,
+       .quartz_direct = 1,
+
+       .agc_config_count = 1,
+       .agc = &stk7700p_7000m_mt2060_agc_config,
+       .bw  = &stk7700p_pll_config,
+
+       .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+static struct dib7000p_config stk7700p_dib7000p_config = {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc = &stk7700p_7000p_mt2060_agc_config,
+       .bw  = &stk7700p_pll_config,
+
+       .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
 };
-*/
 
 static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
 {
+       struct dib0700_state *st = adap->dev->priv;
        /* unless there is no real power management in DVB - we leave the device on GPIO6 */
-       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
-       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
-       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(50);
+
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9,  GPIO_OUT, 1);
+
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
+
+       dib0700_set_gpio(adap->dev,  GPIO0, GPIO_OUT, 1);
+
+       st->mt2060_if1[0] = 1220;
+
+       if (dib7000pc_detection(&adap->dev->i2c_adap)) {
+               adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
+               st->is_dib7000pc = 1;
+       } else
+               adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
 
-//     adap->fe = dib7000m_attach(&adap->dev->i2c_adap, &stk7700p_dib7000m_config, 18);
-       return 0;
+       return adap->fe == NULL ? -ENODEV : 0;
 }
 
+static struct mt2060_config stk7700p_mt2060_config = {
+       0x60
+};
+
 static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 {
-//     tun_i2c = dib7000m_get_tuner_i2c_master(adap->fe, 1);
-//     return mt2060_attach(adap->fe, tun_i2c, &stk3000p_mt2060_config, if1);
-       return 0;
+       struct dib0700_state *st = adap->dev->priv;
+       struct i2c_adapter *tun_i2c;
+
+       if (st->is_dib7000pc)
+               tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       else
+               tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+       return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
+               st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
 }
 
 struct usb_device_id dib0700_usb_id_table[] = {
                { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
+               { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
+
                { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
                { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
                { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
                { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+               { USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
+               { USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
+               { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
+               { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
+               { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
                { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -167,20 +321,32 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 3,
+               .num_device_descs = 6,
                .devices = {
                        {   "DiBcom STK7700P reference design",
-                               { &dib0700_usb_id_table[0], NULL },
+                               { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
                                { NULL },
                        },
                        {   "Hauppauge Nova-T Stick",
-                               { &dib0700_usb_id_table[3], NULL },
+                               { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
                                { NULL },
                        },
                        {   "AVerMedia AVerTV DVB-T Volar",
-                               { &dib0700_usb_id_table[4], NULL },
+                               { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
                                { NULL },
                        },
+                       {   "Compro Videomate U500",
+                               { &dib0700_usb_id_table[6], NULL },
+                               { NULL },
+                       },
+                       {   "Uniwill STK7700P based (Hama and others)",
+                               { &dib0700_usb_id_table[7], NULL },
+                               { NULL },
+                       },
+                       {   "Leadtek Winfast DTV Dongle (STK7700P based)",
+                               { &dib0700_usb_id_table[8], NULL },
+                               { NULL },
+                       }
                }
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
@@ -202,7 +368,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                .num_device_descs = 1,
                .devices = {
                        {   "Hauppauge Nova-T 500 Dual DVB-T",
-                               { &dib0700_usb_id_table[1], &dib0700_usb_id_table[2], NULL },
+                               { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
                                { NULL },
                        },
                }
index 4fe363e48352b753b0359706bc33c3731582fb36..7a6ae8f482e0634f87f95f33d1707ce63681cb36 100644 (file)
@@ -163,23 +163,23 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
-       .streaming_ctrl   = dibusb_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
-       .tuner_attach     = dibusb_tuner_probe_and_attach,
+                       .streaming_ctrl   = dibusb_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+                       .tuner_attach     = dibusb_tuner_probe_and_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
@@ -248,23 +248,23 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
                        .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
                        .pid_filter_count = 16,
 
-       .streaming_ctrl   = dibusb_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
-       .tuner_attach     = dibusb_tuner_probe_and_attach,
+                       .streaming_ctrl   = dibusb_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+                       .tuner_attach     = dibusb_tuner_probe_and_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct dibusb_state),
                },
        },
@@ -312,22 +312,23 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
-       .tuner_attach     = dibusb_thomson_tuner_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+                       .tuner_attach     = dibusb_thomson_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
@@ -369,22 +370,22 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 16,
 
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
-       .tuner_attach     = dibusb_tuner_probe_and_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+                       .tuner_attach     = dibusb_tuner_probe_and_attach,
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index a0fd37efc04b0706a92c7bc192e00571d65528d6..e7ea3e753d6da2eb287af30cb9b245214352b20b 100644 (file)
@@ -54,23 +54,23 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
                {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
-       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+                       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
 
        /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
        },
index 8fb34375c1fbeb1548c931de9b00cc419e88117d..4a198d4755b0699f818d08c83ba73e9093b41037 100644 (file)
@@ -274,20 +274,20 @@ static struct dvb_usb_device_properties digitv_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .frontend_attach  = digitv_frontend_attach,
-       .tuner_attach     = digitv_tuner_attach,
+                       .frontend_attach  = digitv_frontend_attach,
+                       .tuner_attach     = digitv_tuner_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                }
        },
        .identify_state   = digitv_identify_state,
index fa43a41d753b6a8b1e99b9e7512aaf83141699f8..7dbe14321019a36c2c89ee24ea37ca3bff23bc06 100644 (file)
@@ -268,20 +268,20 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
                        .pid_filter_count = 15,
 
-       .streaming_ctrl  = dtt200u_streaming_ctrl,
-       .pid_filter      = dtt200u_pid_filter,
-       .frontend_attach = dtt200u_frontend_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .streaming_ctrl  = dtt200u_streaming_ctrl,
+                       .pid_filter      = dtt200u_pid_filter,
+                       .frontend_attach = dtt200u_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                }
        },
        .power_ctrl      = dtt200u_power_ctrl,
index 4d6b069536ce387575dacf11278f1d73c61862f9..299382dcb81d35bbdf0245fd546379a04a73a095 100644 (file)
@@ -33,6 +33,7 @@
 #define USB_VID_VISIONPLUS                     0x13d3
 #define USB_VID_TWINHAN                                0x1822
 #define USB_VID_ULTIMA_ELECTRONIC              0x05d8
+#define USB_VID_UNIWILL                                0x1584
 #define USB_VID_WIDEVIEW                       0x14aa
 
 /* Product IDs */
@@ -46,6 +47,7 @@
 #define USB_PID_COMPRO_DVBU2000_WARM                   0xd001
 #define USB_PID_COMPRO_DVBU2000_UNK_COLD               0x010c
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
+#define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
@@ -53,7 +55,9 @@
 #define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
 #define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
 #define USB_PID_DIBCOM_STK7700P                                0x1e14
+#define USB_PID_DIBCOM_STK7700P_PC                     0x1e78
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
+#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_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_HAUPPAUGE_NOVA_T_500                   0x9941
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2                 0x9950
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK                 0x7050
-#define USB_PID_AVERMEDIA_VOLAR                                0x1234
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2               0x7060
+#define USB_PID_AVERMEDIA_VOLAR                                0xa807
+#define USB_PID_AVERMEDIA_VOLAR_2                      0xb808
 #define USB_PID_NEBULA_DIGITV                          0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
 #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM             0xdb51
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD             0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM             0xdb59
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD        0xdb54
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM        0xdb55
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM                0xdb55
 #define USB_PID_MEDION_MD95700                         0x0932
 #define USB_PID_KYE_DVB_T_COLD                         0x701e
 #define USB_PID_KYE_DVB_T_WARM                         0x701f
 #define USB_PID_GRANDTEC_DVBT_USB2_WARM                        0x0bc7
 #define USB_PID_WINFAST_DTV_DONGLE_COLD                        0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM                        0x6026
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
 #define USB_PID_GENPIX_8PSK_COLD                       0x0200
 #define USB_PID_GENPIX_8PSK_WARM                       0x0201
 
+
 #endif
index 794e4471561c3fd7e365769bf242701237ff0059..19ff5978bc914f675fc1108bfe01f0d11abaa1dc 100644 (file)
@@ -90,7 +90,9 @@ schedule:
 
 int dvb_usb_remote_init(struct dvb_usb_device *d)
 {
+       struct input_dev *input_dev;
        int i;
+       int err;
 
        if (d->props.rc_key_map == NULL ||
                d->props.rc_query == NULL ||
@@ -100,23 +102,24 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
        strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
 
-       d->rc_input_dev = input_allocate_device();
-       if (!d->rc_input_dev)
+       input_dev = input_allocate_device();
+       if (!input_dev)
                return -ENOMEM;
 
-       d->rc_input_dev->evbit[0] = BIT(EV_KEY);
-       d->rc_input_dev->keycodesize = sizeof(unsigned char);
-       d->rc_input_dev->keycodemax = KEY_MAX;
-       d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver";
-       d->rc_input_dev->phys = d->rc_phys;
-       usb_to_input_id(d->udev, &d->rc_input_dev->id);
-       d->rc_input_dev->cdev.dev = &d->udev->dev;
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->keycodesize = sizeof(unsigned char);
+       input_dev->keycodemax = KEY_MAX;
+       input_dev->name = "IR-receiver inside an USB DVB receiver";
+       input_dev->phys = d->rc_phys;
+       usb_to_input_id(d->udev, &input_dev->id);
+       input_dev->cdev.dev = &d->udev->dev;
 
        /* set the bits for the keys */
        deb_rc("key map size: %d\n", d->props.rc_key_map_size);
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i);
-               set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit);
+               deb_rc("setting bit for event %d item %d\n",
+                       d->props.rc_key_map[i].event, i);
+               set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
        }
 
        /* Start the remote-control polling. */
@@ -124,10 +127,16 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
                d->props.rc_interval = 100; /* default */
 
        /* setting these two values to non-zero, we have to manage key repeats */
-       d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval;
-       d->rc_input_dev->rep[REP_DELAY]  = d->props.rc_interval + 150;
+       input_dev->rep[REP_PERIOD] = d->props.rc_interval;
+       input_dev->rep[REP_DELAY]  = d->props.rc_interval + 150;
 
-       input_register_device(d->rc_input_dev);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+
+       d->rc_input_dev = input_dev;
 
        INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
 
index 7375eb20166dfecb39497d5d91abf3f138c17eeb..518d67fca5e89d4636a11810b6edf2a21539765a 100644 (file)
@@ -194,19 +194,19 @@ static struct dvb_usb_device_properties gp8psk_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = gp8psk_streaming_ctrl,
-       .frontend_attach  = gp8psk_frontend_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .streaming_ctrl   = gp8psk_streaming_ctrl,
+                       .frontend_attach  = gp8psk_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x82,
-               .u = {
-                       .bulk = {
-                               .buffersize = 8192,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 8192,
+                                       }
+                               }
+                       },
                }
        },
        .power_ctrl       = gp8psk_power_ctrl,
index a58874c790b20505d7db03213995b8bb14b66bcc..d48622e76b1bf389ec8fe7af367e2530a0635297 100644 (file)
@@ -163,23 +163,23 @@ static struct dvb_usb_device_properties nova_t_properties = {
                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .pid_filter_count = 32,
 
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .pid_filter       = dibusb_pid_filter,
-       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
-       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
-       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
-
-       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .pid_filter       = dibusb_pid_filter,
+                       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+                       .frontend_attach  = dibusb_dib3000mc_frontend_attach,
+                       .tuner_attach     = dibusb_dib3000mc_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                                       .stream = {
+                                               .type = USB_BULK,
+                               .count = 7,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
 
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
new file mode 100644 (file)
index 0000000..95d2997
--- /dev/null
@@ -0,0 +1,270 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
+ *
+ * TDA8263 + TDA10086
+ *
+ * I2C addresses:
+ * 0x08 - LNBP21PD   - LNB power supply
+ * 0x0e - TDA10086   - Demodulator
+ * 0x50 - FX2 eeprom
+ * 0x60 - TDA8263    - Tuner
+ * 0x78 ???
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#define DVB_USB_LOG_PREFIX "ttusb2"
+#include "dvb-usb.h"
+
+#include "ttusb2.h"
+
+#include "tda826x.h"
+#include "tda10086.h"
+#include "lnbp21.h"
+
+/* debug */
+static int dvb_usb_ttusb2_debug;
+#define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
+module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
+
+struct ttusb2_state {
+       u8 id;
+};
+
+static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
+               u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       struct ttusb2_state *st = d->priv;
+       u8 s[wlen+4],r[64] = { 0 };
+       int ret = 0;
+
+       memset(s,0,wlen+4);
+
+       s[0] = 0xaa;
+       s[1] = ++st->id;
+       s[2] = cmd;
+       s[3] = wlen;
+       memcpy(&s[4],wbuf,wlen);
+
+       ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
+
+       if (ret  != 0 ||
+               r[0] != 0x55 ||
+               r[1] != s[1] ||
+               r[2] != cmd ||
+               (rlen > 0 && r[3] != rlen)) {
+               warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
+               return -EIO;
+       }
+
+       if (rlen > 0)
+               memcpy(rbuf, &r[4], rlen);
+
+       return 0;
+}
+
+static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       static u8 obuf[60], ibuf[60];
+       int i,read;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num > 2)
+               warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+       for (i = 0; i < num; i++) {
+               read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+
+               obuf[0] = (msg[i].addr << 1) | read;
+               obuf[1] = msg[i].len;
+
+               /* read request */
+               if (read)
+                       obuf[2] = msg[i+1].len;
+               else
+                       obuf[2] = 0;
+
+               memcpy(&obuf[3],msg[i].buf,msg[i].len);
+
+               if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
+                       err("i2c transfer failed.");
+                       break;
+               }
+
+               if (read) {
+                       memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
+                       i++;
+               }
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+}
+
+static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm ttusb2_i2c_algo = {
+       .master_xfer   = ttusb2_i2c_xfer,
+       .functionality = ttusb2_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int ttusb2_identify_state (struct usb_device *udev, struct
+               dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
+               int *cold)
+{
+       *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+       return 0;
+}
+
+static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       u8 b = onoff;
+       ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
+       return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
+}
+
+
+static struct tda10086_config tda10086_config = {
+       .demod_address = 0x0e,
+       .invert = 0,
+};
+
+static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       if (usb_set_interface(adap->dev->udev,0,3) < 0)
+               err("set interface to alts=3 failed");
+
+       if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
+               deb_info("TDA10086 attach failed\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
+               deb_info("TDA8263 attach failed\n");
+               return -ENODEV;
+       }
+
+       if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
+               deb_info("LNBP21 attach failed\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties ttusb2_properties;
+
+static int ttusb2_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id ttusb2_table [] = {
+               { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+               {}              /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, ttusb2_table);
+
+static struct dvb_usb_device_properties ttusb2_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware = "dvb-usb-pctv-400e-01.fw",
+
+       .size_of_priv = sizeof(struct ttusb2_state),
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
+
+                       .frontend_attach  = ttusb2_frontend_attach,
+                       .tuner_attach     = ttusb2_tuner_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_ISOC,
+                               .count = 5,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 4,
+                                               .framesize = 940,
+                                               .interval = 1,
+                                       }
+                               }
+                       }
+               }
+       },
+
+       .power_ctrl       = ttusb2_power_ctrl,
+       .identify_state   = ttusb2_identify_state,
+
+       .i2c_algo         = &ttusb2_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "Pinnacle 400e DVB-S USB2.0",
+                       { &ttusb2_table[0], NULL },
+                       { NULL },
+               },
+       }
+};
+
+static struct usb_driver ttusb2_driver = {
+       .name           = "dvb_usb_ttusb2",
+       .probe          = ttusb2_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table       = ttusb2_table,
+};
+
+/* module stuff */
+static int __init ttusb2_module_init(void)
+{
+       int result;
+       if ((result = usb_register(&ttusb2_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit ttusb2_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&ttusb2_driver);
+}
+
+module_init (ttusb2_module_init);
+module_exit (ttusb2_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/dvb/dvb-usb/ttusb2.h
new file mode 100644 (file)
index 0000000..52a63af
--- /dev/null
@@ -0,0 +1,70 @@
+/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
+ * (e.g. Pinnacle 400e DVB-S USB2.0).
+ *
+ * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
+ * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_TTUSB2_H_
+#define _DVB_USB_TTUSB2_H_
+
+/* TTUSB protocol
+ *
+ * always to messages (out/in)
+ * out message:
+ * 0xaa <id> <cmdbyte> <datalen> <data...>
+ *
+ * in message (complete block is always 0x40 bytes long)
+ * 0x55 <id> <cmdbyte> <datalen> <data...>
+ *
+ * id is incremented for each transaction
+ */
+
+#define CMD_DSP_DOWNLOAD    0x13
+/* out data: <byte>[28]
+ * last block must be empty */
+
+#define CMD_DSP_BOOT        0x14
+/* out data: nothing */
+
+#define CMD_POWER           0x15
+/* out data: <on=1/off=0> */
+
+#define CMD_LNB             0x16
+/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
+
+#define CMD_GET_VERSION     0x17
+/* in  data: <version_byte>[5] */
+
+#define CMD_DISEQC          0x18
+/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
+
+#define CMD_PID_ENABLE      0x22
+/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
+
+#define CMD_PID_DISABLE     0x23
+/* out data: <index> */
+
+#define CMD_FILTER_ENABLE   0x24
+/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
+
+#define CMD_FILTER_DISABLE  0x25
+/* out data: <index> */
+
+#define CMD_GET_DSP_VERSION 0x26
+/* in  data: <version_byte>[28] */
+
+#define CMD_I2C_XFER        0x31
+/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
+ * in  data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
+
+#define CMD_I2C_BITRATE     0x32
+/* out data: <default=0> */
+
+#endif
index f9941ea88b3e5996de3d7ecbbc061fc0e44b3b5e..f77b48f76582001958db7eb53ccad7249e9b190e 100644 (file)
@@ -99,21 +99,21 @@ static struct dvb_usb_device_properties umt_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
-       .frontend_attach  = umt_mt352_frontend_attach,
-       .tuner_attach     = umt_tuner_attach,
+                       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+                       .frontend_attach  = umt_mt352_frontend_attach,
+                       .tuner_attach     = umt_tuner_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 20,
-               .endpoint = 0x06,
-               .u = {
-                       .bulk = {
-                               .buffersize = 512,
-                       }
-               }
-       },
+                               .count = 20,
+                               .endpoint = 0x06,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 512,
+                                       }
+                               }
+                       },
 
                        .size_of_priv     = sizeof(struct dibusb_state),
                }
index 02bd61aaac666b3c6d1b5156ccc1d597dbda2f0b..16533b31a82dd6a10c7b10fc672dd53eaf0e0f6a 100644 (file)
@@ -275,22 +275,22 @@ static struct dvb_usb_device_properties vp702x_properties = {
                        .caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
 
                        .streaming_ctrl   = vp702x_streaming_ctrl,
-       .frontend_attach  = vp702x_frontend_attach,
+                       .frontend_attach  = vp702x_frontend_attach,
 
-       /* parameter for the MPEG2-data transfer */
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
                                .count = 10,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                        .size_of_priv     = sizeof(struct vp702x_state),
                }
-               },
+       },
        .read_mac_address = vp702x_read_mac_addr,
 
        .rc_key_map       = vp702x_rc_keys,
index b4cf002703a753dd0e4be529ca5e29b7d92d9952..69a46b3607a2a1d63e42dc2daacb2983896039c8 100644 (file)
@@ -125,7 +125,25 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = {
        { 0x00, 0x00, KEY_TAB }, /* Tab */
        { 0x00, 0x48, KEY_INFO }, /* Preview */
        { 0x00, 0x04, KEY_LIST }, /* RecordList */
-       { 0x00, 0x0f, KEY_TEXT } /* Teletext */
+       { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
+       { 0x00, 0x41, KEY_PREVIOUSSONG },
+       { 0x00, 0x42, KEY_NEXTSONG },
+       { 0x00, 0x4b, KEY_UP },
+       { 0x00, 0x51, KEY_DOWN },
+       { 0x00, 0x4e, KEY_LEFT },
+       { 0x00, 0x52, KEY_RIGHT },
+       { 0x00, 0x4f, KEY_ENTER },
+       { 0x00, 0x13, KEY_CANCEL },
+       { 0x00, 0x4a, KEY_CLEAR },
+       { 0x00, 0x54, KEY_PRINT }, /* Capture */
+       { 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */
+       { 0x00, 0x08, KEY_VIDEO }, /* A/V */
+       { 0x00, 0x07, KEY_SLEEP }, /* Hibernate */
+       { 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */
+       { 0x00, 0x18, KEY_RED},
+       { 0x00, 0x53, KEY_GREEN},
+       { 0x00, 0x5e, KEY_YELLOW},
+       { 0x00, 0x5f, KEY_BLUE}
 };
 
 static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -217,18 +235,18 @@ static struct dvb_usb_device_properties vp7045_properties = {
        .num_adapters = 1,
        .adapter = {
                {
-       .frontend_attach  = vp7045_frontend_attach,
-       /* parameter for the MPEG2-data transfer */
+                       .frontend_attach  = vp7045_frontend_attach,
+                       /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-               .count = 7,
-               .endpoint = 0x02,
-               .u = {
-                       .bulk = {
-                               .buffersize = 4096,
-                       }
-               }
-       },
+                               .count = 7,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
                }
        },
        .power_ctrl       = vp7045_power_ctrl,
index aebb8d6f26f83a853d3b67f3b6ce8fc0cb01d6ef..af314bb1dcac47b35a4435949bff85a4ede0afb8 100644 (file)
@@ -172,6 +172,22 @@ config DVB_DIB3000MC
          A DVB-T tuner module. Designed for mobile usage. Say Y when you want
          to support this frontend.
 
+config DVB_DIB7000M
+       tristate "DiBcom 7000MA/MB/PA/PB/MC"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+         to support this frontend.
+
+config DVB_DIB7000P
+       tristate "DiBcom 7000PC"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+         to support this frontend.
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
@@ -281,6 +297,14 @@ config DVB_TUNER_MT2060
        help
          A driver for the silicon IF tuner MT2060 from Microtune.
 
+config DVB_TUNER_LGH06XF
+       tristate "LG TDVS-H06xF ATSC tuner"
+       depends on DVB_CORE && I2C
+       select DVB_PLL
+       default m if DVB_FE_CUSTOMISE
+       help
+         A driver for the LG TDVS-H06xF ATSC tuner family.
+
 comment "Miscellaneous devices"
        depends on DVB_CORE
 
index dce9cf0c75c0880acc234ad7a58d5441b3b6286c..3fa6e5d32a9cfa870610db0819943a9936014cdd 100644 (file)
@@ -13,6 +13,8 @@ obj-$(CONFIG_DVB_TDA8083) += tda8083.o
 obj-$(CONFIG_DVB_L64781) += l64781.o
 obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
 obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -37,3 +39,4 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
index 3561a777568c8cd3cee259c2db59c559744a8332..5da66178006ca9ef91d7f60cde30414e155b8198 100644 (file)
@@ -511,16 +511,11 @@ static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000
 
 
        /* a channel for autosearch */
-       reg = 0;
-       if (chan->nfft == -1 && chan->guard == -1) reg = 7;
-       if (chan->nfft == -1 && chan->guard != -1) reg = 2;
-       if (chan->nfft != -1 && chan->guard == -1) reg = 3;
-
        fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
        fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
        fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
 
-       dib3000mc_set_channel_cfg(state, &fchan, reg);
+       dib3000mc_set_channel_cfg(state, &fchan, 7);
 
        reg = dib3000mc_read_word(state, 0);
        dib3000mc_write_word(state, 0, reg | (1 << 8));
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
new file mode 100644 (file)
index 0000000..f5d40aa
--- /dev/null
@@ -0,0 +1,1191 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB7000M and
+ *              first generation DiB7000P-demodulator-family.
+ *
+ * Copyright (C) 2005-6 DiBcom (http://www.dibcom.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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib7000m.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0)
+
+struct dib7000m_state {
+       struct dvb_frontend demod;
+    struct dib7000m_config cfg;
+
+       u8 i2c_addr;
+       struct i2c_adapter   *i2c_adap;
+
+       struct dibx000_i2c_master i2c_master;
+
+/* offset is 1 in case of the 7000MC */
+       u8 reg_offs;
+
+       u16 wbd_ref;
+
+       u8 current_band;
+       fe_bandwidth_t current_bandwidth;
+       struct dibx000_agc_config *current_agc;
+       u32 timf;
+
+       u16 revision;
+};
+
+enum dib7000m_power_mode {
+       DIB7000M_POWER_ALL = 0,
+
+       DIB7000M_POWER_NO,
+       DIB7000M_POWER_INTERF_ANALOG_AGC,
+       DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
+       DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
+       DIB7000M_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+{
+       u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
+       u8 rb[2];
+       struct i2c_msg msg[2] = {
+               { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
+               { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+       };
+
+       if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d\n",reg);
+
+       return (rb[0] << 8) | rb[1];
+}
+
+static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+{
+       u8 b[4] = {
+               (reg >> 8) & 0xff, reg & 0xff,
+               (val >> 8) & 0xff, val & 0xff,
+       };
+       struct i2c_msg msg = {
+               .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+       };
+       return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
+{
+       int    ret = 0;
+       u16 outreg, fifo_threshold, smo_mode,
+               sram = 0x0005; /* by default SRAM output is disabled */
+
+       outreg = 0;
+       fifo_threshold = 1792;
+       smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
+
+       dprintk("-I-  Setting output mode for demod %p to %d\n",
+                       &state->demod, mode);
+
+       switch (mode) {
+               case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
+                       outreg = (1 << 10);  /* 0x0400 */
+                       break;
+               case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
+                       outreg = (1 << 10) | (1 << 6); /* 0x0440 */
+                       break;
+               case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
+                       outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
+                       break;
+               case OUTMODE_DIVERSITY:
+                       if (state->cfg.hostbus_diversity)
+                               outreg = (1 << 10) | (4 << 6); /* 0x0500 */
+                       else
+                               sram   |= 0x0c00;
+                       break;
+               case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
+                       smo_mode |= (3 << 1);
+                       fifo_threshold = 512;
+                       outreg = (1 << 10) | (5 << 6);
+                       break;
+               case OUTMODE_HIGH_Z:  // disable
+                       outreg = 0;
+                       break;
+               default:
+                       dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+                       break;
+       }
+
+       if (state->cfg.output_mpeg2_in_188_bytes)
+               smo_mode |= (1 << 5) ;
+
+       ret |= dib7000m_write_word(state,  294 + state->reg_offs, smo_mode);
+       ret |= dib7000m_write_word(state,  295 + state->reg_offs, fifo_threshold); /* synchronous fread */
+       ret |= dib7000m_write_word(state, 1795, outreg);
+       ret |= dib7000m_write_word(state, 1805, sram);
+
+       return ret;
+}
+
+static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+{
+       /* by default everything is going to be powered off */
+       u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
+
+       /* now, depending on the requested mode, we power on */
+       switch (mode) {
+               /* power up everything in the demod */
+               case DIB7000M_POWER_ALL:
+                       reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
+                       break;
+
+               /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
+               case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
+                       reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
+                       break;
+
+               case DIB7000M_POWER_INTERF_ANALOG_AGC:
+                       reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
+                       reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
+                       reg_906 &= ~((1 << 0));
+                       break;
+
+               case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
+                       reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
+                       break;
+
+               case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
+                       reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
+                       break;
+               case DIB7000M_POWER_NO:
+                       break;
+       }
+
+       /* always power down unused parts */
+       if (!state->cfg.mobile_mode)
+               reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
+
+       /* P_sdio_select_clk = 0 on MC */
+       if (state->revision != 0x4000)
+               reg_906 <<= 1;
+
+       dib7000m_write_word(state,  903,  reg_903);
+       dib7000m_write_word(state,  904,  reg_904);
+       dib7000m_write_word(state,  905,  reg_905);
+       dib7000m_write_word(state,  906,  reg_906);
+
+       return 0;
+}
+
+static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
+{
+       int ret = 0;
+       u16 reg_913 = dib7000m_read_word(state, 913),
+              reg_914 = dib7000m_read_word(state, 914);
+
+       switch (no) {
+               case DIBX000_SLOW_ADC_ON:
+                       reg_914 |= (1 << 1) | (1 << 0);
+                       ret |= dib7000m_write_word(state, 914, reg_914);
+                       reg_914 &= ~(1 << 1);
+                       break;
+
+               case DIBX000_SLOW_ADC_OFF:
+                       reg_914 |=  (1 << 1) | (1 << 0);
+                       break;
+
+               case DIBX000_ADC_ON:
+                       if (state->revision == 0x4000) { // workaround for PA/MA
+                               // power-up ADC
+                               dib7000m_write_word(state, 913, 0);
+                               dib7000m_write_word(state, 914, reg_914 & 0x3);
+                               // power-down bandgag
+                               dib7000m_write_word(state, 913, (1 << 15));
+                               dib7000m_write_word(state, 914, reg_914 & 0x3);
+                       }
+
+                       reg_913 &= 0x0fff;
+                       reg_914 &= 0x0003;
+                       break;
+
+               case DIBX000_ADC_OFF: // leave the VBG voltage on
+                       reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
+                       reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+                       break;
+
+               case DIBX000_VBG_ENABLE:
+                       reg_913 &= ~(1 << 15);
+                       break;
+
+               case DIBX000_VBG_DISABLE:
+                       reg_913 |= (1 << 15);
+                       break;
+
+               default:
+                       break;
+       }
+
+//     dprintk("-D-  913: %x, 914: %x\n", reg_913, reg_914);
+
+       ret |= dib7000m_write_word(state, 913, reg_913);
+       ret |= dib7000m_write_word(state, 914, reg_914);
+
+       return ret;
+}
+
+static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+{
+       struct dib7000m_state *state = demod->demodulator_priv;
+       u32 timf;
+
+       // store the current bandwidth for later use
+       state->current_bandwidth = bw_idx;
+
+       if (state->timf == 0) {
+               dprintk("-D-  Using default timf\n");
+               timf = state->cfg.bw->timf;
+       } else {
+               dprintk("-D-  Using updated timf\n");
+               timf = state->timf;
+       }
+
+       timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+
+       dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
+       dib7000m_write_word(state, 24, (timf      ) & 0xffff);
+
+       return 0;
+}
+
+static int dib7000m_sad_calib(struct dib7000m_state *state)
+{
+
+/* internal */
+//     dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+       dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
+       dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
+
+       /* do the calibration */
+       dib7000m_write_word(state, 929, (1 << 0));
+       dib7000m_write_word(state, 929, (0 << 0));
+
+       msleep(1);
+
+       return 0;
+}
+
+static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
+{
+       dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
+       dib7000m_write_word(state, 19,  (bw->internal*1000)        & 0xffff);
+       dib7000m_write_word(state, 21,  (bw->ifreq          >> 16) & 0xffff);
+       dib7000m_write_word(state, 22,   bw->ifreq                 & 0xffff);
+
+       dib7000m_write_word(state, 928, bw->sad_cfg);
+}
+
+static void dib7000m_reset_pll(struct dib7000m_state *state)
+{
+       const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+       u16 reg_907,reg_910;
+
+       /* default */
+       reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
+               (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
+               (bw->enable_refdiv << 1) | (0 << 0);
+       reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
+
+       // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
+       // this is only working only for 30 MHz crystals
+       if (!state->cfg.quartz_direct) {
+               reg_910 |= (1 << 5);  // forcing the predivider to 1
+
+               // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
+               if(state->cfg.input_clk_is_div_2)
+                       reg_907 |= (16 << 9);
+               else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
+                       reg_907 |= (8 << 9);
+       } else {
+               reg_907 |= (bw->pll_ratio & 0x3f) << 9;
+               reg_910 |= (bw->pll_prediv << 5);
+       }
+
+       dib7000m_write_word(state, 910, reg_910); // pll cfg
+       dib7000m_write_word(state, 907, reg_907); // clk cfg0
+       dib7000m_write_word(state, 908, 0x0006);  // clk_cfg1
+
+       dib7000m_reset_pll_common(state, bw);
+}
+
+static void dib7000mc_reset_pll(struct dib7000m_state *state)
+{
+       const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+
+       // clk_cfg0
+       dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
+
+       // clk_cfg1
+       //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
+       dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+                       (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
+                       (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+
+       // smpl_cfg
+       dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
+
+       dib7000m_reset_pll_common(state, bw);
+}
+
+static int dib7000m_reset_gpio(struct dib7000m_state *st)
+{
+       /* reset the GPIOs */
+       dprintk("-D-  gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
+               st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
+
+       dib7000m_write_word(st, 773, st->cfg.gpio_dir);
+       dib7000m_write_word(st, 774, st->cfg.gpio_val);
+
+       /* TODO 782 is P_gpio_od */
+
+       dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
+
+       dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
+       return 0;
+}
+
+static int dib7000m_demod_reset(struct dib7000m_state *state)
+{
+       dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+       /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
+       dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+       /* restart all parts */
+       dib7000m_write_word(state,  898, 0xffff);
+       dib7000m_write_word(state,  899, 0xffff);
+       dib7000m_write_word(state,  900, 0xff0f);
+       dib7000m_write_word(state,  901, 0xfffc);
+
+       dib7000m_write_word(state,  898, 0);
+       dib7000m_write_word(state,  899, 0);
+       dib7000m_write_word(state,  900, 0);
+       dib7000m_write_word(state,  901, 0);
+
+       if (state->revision == 0x4000)
+               dib7000m_reset_pll(state);
+       else
+               dib7000mc_reset_pll(state);
+
+       if (dib7000m_reset_gpio(state) != 0)
+               dprintk("-E-  GPIO reset was not successful.\n");
+
+       if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+               dprintk("-E-  OUTPUT_MODE could not be resetted.\n");
+
+       /* unforce divstr regardless whether i2c enumeration was done or not */
+       dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
+
+       dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+
+       dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+       dib7000m_sad_calib(state);
+       dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+       dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+
+       return 0;
+}
+
+static void dib7000m_restart_agc(struct dib7000m_state *state)
+{
+       // P_restart_iqc & P_restart_agc
+       dib7000m_write_word(state, 898, 0x0c00);
+       dib7000m_write_word(state, 898, 0x0000);
+}
+
+static int dib7000m_agc_soft_split(struct dib7000m_state *state)
+{
+       u16 agc,split_offset;
+
+       if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
+               return 0;
+
+       // n_agc_global
+       agc = dib7000m_read_word(state, 390);
+
+       if (agc > state->current_agc->split.min_thres)
+               split_offset = state->current_agc->split.min;
+       else if (agc < state->current_agc->split.max_thres)
+               split_offset = state->current_agc->split.max;
+       else
+               split_offset = state->current_agc->split.max *
+                       (agc - state->current_agc->split.min_thres) /
+                       (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
+
+       dprintk("AGC split_offset: %d\n",split_offset);
+
+       // P_agc_force_split and P_agc_split_offset
+       return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
+}
+
+static int dib7000m_update_lna(struct dib7000m_state *state)
+{
+       int i;
+       u16 dyn_gain;
+
+       // when there is no LNA to program return immediatly
+       if (state->cfg.update_lna == NULL)
+               return 0;
+
+       msleep(60);
+       for (i = 0; i < 20; i++) {
+               // read dyn_gain here (because it is demod-dependent and not tuner)
+               dyn_gain = dib7000m_read_word(state, 390);
+
+               dprintk("agc global: %d\n", dyn_gain);
+
+               if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+                       dib7000m_restart_agc(state);
+                       msleep(60);
+               } else
+                       break;
+       }
+       return 0;
+}
+
+static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+{
+       struct dibx000_agc_config *agc = NULL;
+       int i;
+       if (state->current_band == band)
+               return;
+       state->current_band = band;
+
+       for (i = 0; i < state->cfg.agc_config_count; i++)
+               if (state->cfg.agc[i].band_caps & band) {
+                       agc = &state->cfg.agc[i];
+                       break;
+               }
+
+       if (agc == NULL) {
+               dprintk("-E-  No valid AGC configuration found for band 0x%02x\n",band);
+               return;
+       }
+
+       state->current_agc = agc;
+
+       /* AGC */
+       dib7000m_write_word(state, 72 ,  agc->setup);
+       dib7000m_write_word(state, 73 ,  agc->inv_gain);
+       dib7000m_write_word(state, 74 ,  agc->time_stabiliz);
+       dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
+
+       // Demod AGC loop configuration
+       dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
+       dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
+
+       dprintk("-D-  WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+               state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+       /* AGC continued */
+       if (state->wbd_ref != 0)
+               dib7000m_write_word(state, 102, state->wbd_ref);
+       else // use default
+               dib7000m_write_word(state, 102, agc->wbd_ref);
+
+       dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
+       dib7000m_write_word(state, 104,  agc->agc1_max);
+       dib7000m_write_word(state, 105,  agc->agc1_min);
+       dib7000m_write_word(state, 106,  agc->agc2_max);
+       dib7000m_write_word(state, 107,  agc->agc2_min);
+       dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
+       dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+       dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+       dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+       if (state->revision > 0x4000) { // settings for the MC
+               dib7000m_write_word(state, 71,   agc->agc1_pt3);
+//             dprintk("-D-  929: %x %d %d\n",
+//                     (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
+               dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
+       } else {
+               // wrong default values
+               u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
+               for (i = 0; i < 9; i++)
+                       dib7000m_write_word(state, 88 + i, b[i]);
+       }
+}
+
+static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+{
+       u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
+       state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+       dib7000m_write_word(state, 23, (u16) (timf >> 16));
+       dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
+       dprintk("-D-  Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+}
+
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+{
+       u16 value, est[4];
+
+       dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+
+       /* nfft, guard, qam, alpha */
+       dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+       dib7000m_write_word(state, 5, (seq << 4));
+
+       /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
+       value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
+       if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
+               value |= (ch->vit_code_rate_hp << 1);
+       else
+               value |= (ch->vit_code_rate_lp << 1);
+       dib7000m_write_word(state, 267 + state->reg_offs, value);
+
+       /* offset loop parameters */
+
+       /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
+       dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
+
+       /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+       dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+       /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
+       dib7000m_write_word(state, 32, (0 << 4) | 0x3);
+
+       /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
+       dib7000m_write_word(state, 33, (0 << 4) | 0x5);
+
+       /* P_dvsy_sync_wait */
+       switch (ch->nfft) {
+               case 1: value = 256; break;
+               case 2: value = 128; break;
+               case 0:
+               default: value = 64; break;
+       }
+       value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
+       value <<= 4;
+
+       /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
+       /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+       if (ch->intlv_native || state->revision > 0x4000)
+               value |= (1 << 2) | (2 << 0);
+       else
+               value |= 0;
+       dib7000m_write_word(state, 266 + state->reg_offs, value);
+
+       /* channel estimation fine configuration */
+       switch (ch->nqam) {
+               case 2:
+                       est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
+                       est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
+                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
+                       break;
+               case 1:
+                       est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
+                       est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
+                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+                       est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
+                       break;
+               default:
+                       est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
+                       est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
+                       est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
+                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
+                       break;
+       }
+       for (value = 0; value < 4; value++)
+               dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
+
+       // set power-up level: interf+analog+AGC
+       dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+       dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+       msleep(7);
+
+       //AGC initialization
+       if (state->cfg.agc_control)
+               state->cfg.agc_control(&state->demod, 1);
+
+       dib7000m_restart_agc(state);
+
+       // wait AGC rough lock time
+       msleep(5);
+
+       dib7000m_update_lna(state);
+       dib7000m_agc_soft_split(state);
+
+       // wait AGC accurate lock time
+       msleep(7);
+
+       if (state->cfg.agc_control)
+               state->cfg.agc_control(&state->demod, 0);
+
+       // set power-up level: autosearch
+       dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
+}
+
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+       struct dib7000m_state *state = demod->demodulator_priv;
+       struct dibx000_ofdm_channel auto_ch;
+       int ret = 0;
+       u32 value;
+
+       INIT_OFDM_CHANNEL(&auto_ch);
+       auto_ch.RF_kHz           = ch->RF_kHz;
+       auto_ch.Bw               = ch->Bw;
+       auto_ch.nqam             = 2;
+       auto_ch.guard            = 0;
+       auto_ch.nfft             = 1;
+       auto_ch.vit_alpha        = 1;
+       auto_ch.vit_select_hp    = 1;
+       auto_ch.vit_code_rate_hp = 2;
+       auto_ch.vit_code_rate_lp = 3;
+       auto_ch.vit_hrch         = 0;
+       auto_ch.intlv_native     = 1;
+
+       dib7000m_set_channel(state, &auto_ch, 7);
+
+       // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
+       value = 30 * state->cfg.bw->internal;
+       ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
+       ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
+       value = 100 * state->cfg.bw->internal;
+       ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
+       ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
+       value = 500 * state->cfg.bw->internal;
+       ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
+       ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
+
+       // start search
+       value = dib7000m_read_word(state, 0);
+       ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+
+       /* clear n_irq_pending */
+       if (state->revision == 0x4000)
+               dib7000m_write_word(state, 1793, 0);
+       else
+               dib7000m_read_word(state, 537);
+
+       ret |= dib7000m_write_word(state, 0, (u16) value);
+
+       return ret;
+}
+
+static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
+{
+       u16 irq_pending = dib7000m_read_word(state, reg);
+
+       if (irq_pending & 0x1) { // failed
+               dprintk("#\n");
+               return 1;
+       }
+
+       if (irq_pending & 0x2) { // succeeded
+               dprintk("!\n");
+               return 2;
+       }
+       return 0; // still pending
+}
+
+static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
+{
+       struct dib7000m_state *state = demod->demodulator_priv;
+       if (state->revision == 0x4000)
+               return dib7000m_autosearch_irq(state, 1793);
+       else
+               return dib7000m_autosearch_irq(state, 537);
+}
+
+static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+       struct dib7000m_state *state = demod->demodulator_priv;
+       int ret = 0;
+       u16 value;
+
+       // we are already tuned - just resuming from suspend
+       if (ch != NULL)
+               dib7000m_set_channel(state, ch, 0);
+       else
+               return -EINVAL;
+
+       // restart demod
+       ret |= dib7000m_write_word(state, 898, 0x4000);
+       ret |= dib7000m_write_word(state, 898, 0x0000);
+       msleep(45);
+
+       ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+       /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+       ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+       // never achieved a lock with that bandwidth so far - wait for timfreq to update
+       if (state->timf == 0)
+               msleep(200);
+
+       //dump_reg(state);
+       /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+       value = (6 << 8) | 0x80;
+       switch (ch->nfft) {
+               case 0: value |= (7 << 12); break;
+               case 1: value |= (9 << 12); break;
+               case 2: value |= (8 << 12); break;
+       }
+       ret |= dib7000m_write_word(state, 26, value);
+
+       /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+       value = (0 << 4);
+       switch (ch->nfft) {
+               case 0: value |= 0x6; break;
+               case 1: value |= 0x8; break;
+               case 2: value |= 0x7; break;
+       }
+       ret |= dib7000m_write_word(state, 32, value);
+
+       /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+       value = (0 << 4);
+       switch (ch->nfft) {
+               case 0: value |= 0x6; break;
+               case 1: value |= 0x8; break;
+               case 2: value |= 0x7; break;
+       }
+       ret |= dib7000m_write_word(state, 33,  value);
+
+       // we achieved a lock - it's time to update the osc freq
+       if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
+               dib7000m_update_timf_freq(state);
+
+       return ret;
+}
+
+static int dib7000m_init(struct dvb_frontend *demod)
+{
+       struct dib7000m_state *state = demod->demodulator_priv;
+       int ret = 0;
+       u8 o = state->reg_offs;
+
+       dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
+
+       if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
+               dprintk("-E-  could not start Slow ADC\n");
+
+       if (state->cfg.dvbt_mode)
+               dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+       if (state->cfg.mobile_mode)
+               ret |= dib7000m_write_word(state, 261 + o, 2);
+       else
+               ret |= dib7000m_write_word(state, 224 + o, 1);
+
+       ret |= dib7000m_write_word(state, 173 + o, 0);
+       ret |= dib7000m_write_word(state, 174 + o, 0);
+       ret |= dib7000m_write_word(state, 175 + o, 0);
+       ret |= dib7000m_write_word(state, 176 + o, 0);
+       ret |= dib7000m_write_word(state, 177 + o, 0);
+       ret |= dib7000m_write_word(state, 178 + o, 0);
+       ret |= dib7000m_write_word(state, 179 + o, 0);
+       ret |= dib7000m_write_word(state, 180 + o, 0);
+
+       // P_corm_thres Lock algorithms configuration
+       ret |= dib7000m_write_word(state, 26, 0x6680);
+
+       // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+       ret |= dib7000m_write_word(state, 170 + o, 0x0410);
+       // P_fft_nb_to_cut
+       ret |= dib7000m_write_word(state, 182 + o, 8192);
+       // P_pha3_thres
+       ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
+       // P_cti_use_cpe, P_cti_use_prog
+       ret |= dib7000m_write_word(state, 196 + o,     0);
+       // P_cspu_regul, P_cspu_win_cut
+       ret |= dib7000m_write_word(state, 205 + o, 0x200f);
+       // P_adp_regul_cnt
+       ret |= dib7000m_write_word(state, 214 + o, 0x023d);
+       // P_adp_noise_cnt
+       ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
+       // P_adp_regul_ext
+       ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
+       // P_adp_noise_ext
+       ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
+       // P_adp_fil
+       ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
+
+       // P_2d_byp_ti_num
+       ret |= dib7000m_write_word(state, 226 + o, 0);
+
+       // P_fec_*
+       ret |= dib7000m_write_word(state, 281 + o, 0x0010);
+       // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+       ret |= dib7000m_write_word(state, 294 + o,0x0062);
+
+       // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+       if(state->cfg.tuner_is_baseband)
+               ret |= dib7000m_write_word(state, 36, 0x0755);
+       else
+               ret |= dib7000m_write_word(state, 36, 0x1f55);
+
+       // auto search configuration
+       ret |= dib7000m_write_word(state, 2,  0x0004);
+       ret |= dib7000m_write_word(state, 3,  0x1000);
+       ret |= dib7000m_write_word(state, 4,  0x0814);
+       ret |= dib7000m_write_word(state, 6,  0x001b);
+       ret |= dib7000m_write_word(state, 7,  0x7740);
+       ret |= dib7000m_write_word(state, 8,  0x005b);
+       ret |= dib7000m_write_word(state, 9,  0x8d80);
+       ret |= dib7000m_write_word(state, 10, 0x01c9);
+       ret |= dib7000m_write_word(state, 11, 0xc380);
+       ret |= dib7000m_write_word(state, 12, 0x0000);
+       ret |= dib7000m_write_word(state, 13, 0x0080);
+       ret |= dib7000m_write_word(state, 14, 0x0000);
+       ret |= dib7000m_write_word(state, 15, 0x0090);
+       ret |= dib7000m_write_word(state, 16, 0x0001);
+       ret |= dib7000m_write_word(state, 17, 0xd4c0);
+       ret |= dib7000m_write_word(state, 263 + o,0x0001);
+
+       // P_divclksel=3 P_divbitsel=1
+       if (state->revision == 0x4000)
+               dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+       else
+               dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+       // Tuner IO bank: max drive (14mA)
+       ret |= dib7000m_write_word(state, 912 ,0x2c8a);
+
+       ret |= dib7000m_write_word(state, 1817, 1);
+
+       return ret;
+}
+
+static int dib7000m_sleep(struct dvb_frontend *demod)
+{
+       struct dib7000m_state *st = demod->demodulator_priv;
+       dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
+       return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
+               dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+               dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
+}
+
+static int dib7000m_identify(struct dib7000m_state *state)
+{
+       u16 value;
+       if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
+               dprintk("-E-  DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+               return -EREMOTEIO;
+       }
+
+       state->revision = dib7000m_read_word(state, 897);
+       if (state->revision != 0x4000 &&
+               state->revision != 0x4001 &&
+               state->revision != 0x4002) {
+               dprintk("-E-  DiB7000M: wrong Device ID (%x)\n",value);
+               return -EREMOTEIO;
+       }
+
+       /* protect this driver to be used with 7000PC */
+       if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
+               dprintk("-E-  DiB7000M: this driver does not work with DiB7000PC\n");
+               return -EREMOTEIO;
+       }
+
+       switch (state->revision) {
+               case 0x4000: dprintk("-I-  found DiB7000MA/PA/MB/PB\n"); break;
+               case 0x4001: state->reg_offs = 1; dprintk("-I-  found DiB7000HC\n"); break;
+               case 0x4002: state->reg_offs = 1; dprintk("-I-  found DiB7000MC\n"); break;
+       }
+
+       return 0;
+}
+
+
+static int dib7000m_get_frontend(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *fep)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       u16 tps = dib7000m_read_word(state,480);
+
+       fep->inversion = INVERSION_AUTO;
+
+       fep->u.ofdm.bandwidth = state->current_bandwidth;
+
+       switch ((tps >> 8) & 0x3) {
+               case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+               case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+               /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+       }
+
+       switch (tps & 0x3) {
+               case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
+               case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
+               case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
+               case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+       }
+
+       switch ((tps >> 14) & 0x3) {
+               case 0: fep->u.ofdm.constellation = QPSK; break;
+               case 1: fep->u.ofdm.constellation = QAM_16; break;
+               case 2:
+               default: fep->u.ofdm.constellation = QAM_64; break;
+       }
+
+       /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+       /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+       fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       switch ((tps >> 5) & 0x7) {
+               case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
+               case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
+               case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
+               case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+               case 7:
+               default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+
+       }
+
+       switch ((tps >> 2) & 0x7) {
+               case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
+               case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
+               case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
+               case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+               case 7:
+               default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+       }
+
+       /* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
+
+       return 0;
+}
+
+static int dib7000m_set_frontend(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *fep)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       struct dibx000_ofdm_channel ch;
+
+       INIT_OFDM_CHANNEL(&ch);
+       FEP2DIB(fep,&ch);
+
+       state->current_bandwidth = fep->u.ofdm.bandwidth;
+       dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, fep);
+
+       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
+               fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
+               fep->u.ofdm.constellation     == QAM_AUTO ||
+               fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+               int i = 800, found;
+
+               dib7000m_autosearch_start(fe, &ch);
+               do {
+                       msleep(1);
+                       found = dib7000m_autosearch_is_irq(fe);
+               } while (found == 0 && i--);
+
+               dprintk("autosearch returns: %d\n",found);
+               if (found == 0 || found == 1)
+                       return 0; // no channel found
+
+               dib7000m_get_frontend(fe, fep);
+               FEP2DIB(fep, &ch);
+       }
+
+       /* make this a config parameter */
+       dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+       return dib7000m_tune(fe, &ch);
+}
+
+static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       u16 lock = dib7000m_read_word(state, 535);
+
+       *stat = 0;
+
+       if (lock & 0x8000)
+               *stat |= FE_HAS_SIGNAL;
+       if (lock & 0x3000)
+               *stat |= FE_HAS_CARRIER;
+       if (lock & 0x0100)
+               *stat |= FE_HAS_VITERBI;
+       if (lock & 0x0010)
+               *stat |= FE_HAS_SYNC;
+       if (lock & 0x0008)
+               *stat |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
+       return 0;
+}
+
+static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       *unc = dib7000m_read_word(state, 534);
+       return 0;
+}
+
+static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       u16 val = dib7000m_read_word(state, 390);
+       *strength = 65535 - val;
+       return 0;
+}
+
+static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       *snr = 0x0000;
+       return 0;
+}
+
+static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 1000;
+       return 0;
+}
+
+static void dib7000m_release(struct dvb_frontend *demod)
+{
+       struct dib7000m_state *st = demod->demodulator_priv;
+       dibx000_exit_i2c_master(&st->i2c_master);
+       kfree(st);
+}
+
+struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+       struct dib7000m_state *st = demod->demodulator_priv;
+       return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000m_get_i2c_master);
+
+int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[])
+{
+       struct dib7000m_state st = { .i2c_adap = i2c };
+       int k = 0;
+       u8 new_addr = 0;
+
+       for (k = no_of_demods-1; k >= 0; k--) {
+               st.cfg = cfg[k];
+
+               /* designated i2c address */
+               new_addr          = (0x40 + k) << 1;
+               st.i2c_addr = new_addr;
+               if (dib7000m_identify(&st) != 0) {
+                       st.i2c_addr = default_addr;
+                       if (dib7000m_identify(&st) != 0) {
+                               dprintk("DiB7000M #%d: not identified\n", k);
+                               return -EIO;
+                       }
+               }
+
+               /* start diversity to pull_down div_str - just for i2c-enumeration */
+               dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
+
+               dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
+
+               /* set new i2c address and force divstart */
+               dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
+
+               dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+       }
+
+       for (k = 0; k < no_of_demods; k++) {
+               st.cfg = cfg[k];
+               st.i2c_addr = (0x40 + k) << 1;
+
+               // unforce divstr
+               dib7000m_write_word(&st,1794, st.i2c_addr << 2);
+
+               /* deactivate div - it was just for i2c-enumeration */
+               dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(dib7000m_i2c_enumeration);
+
+static struct dvb_frontend_ops dib7000m_ops;
+struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
+{
+       struct dvb_frontend *demod;
+       struct dib7000m_state *st;
+       st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
+       if (st == NULL)
+               return NULL;
+
+       memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
+       st->i2c_adap = i2c_adap;
+       st->i2c_addr = i2c_addr;
+
+       demod                   = &st->demod;
+       demod->demodulator_priv = st;
+       memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+
+       if (dib7000m_identify(st) != 0)
+               goto error;
+
+       if (st->revision == 0x4000)
+               dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
+       else
+               dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
+
+       dib7000m_demod_reset(st);
+
+       return demod;
+
+error:
+       kfree(st);
+       return NULL;
+}
+EXPORT_SYMBOL(dib7000m_attach);
+
+static struct dvb_frontend_ops dib7000m_ops = {
+       .info = {
+               .name = "DiBcom 7000MA/MB/PA/PB/MC",
+               .type = FE_OFDM,
+               .frequency_min      = 44250000,
+               .frequency_max      = 867250000,
+               .frequency_stepsize = 62500,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_RECOVER |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release              = dib7000m_release,
+
+       .init                 = dib7000m_init,
+       .sleep                = dib7000m_sleep,
+
+       .set_frontend         = dib7000m_set_frontend,
+       .get_tune_settings    = dib7000m_fe_get_tune_settings,
+       .get_frontend         = dib7000m_get_frontend,
+
+       .read_status          = dib7000m_read_status,
+       .read_ber             = dib7000m_read_ber,
+       .read_signal_strength = dib7000m_read_signal_strength,
+       .read_snr             = dib7000m_read_snr,
+       .read_ucblocks        = dib7000m_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000m.h b/drivers/media/dvb/frontends/dib7000m.h
new file mode 100644 (file)
index 0000000..597e9cc
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DIB7000M_H
+#define DIB7000M_H
+
+#include "dibx000_common.h"
+
+struct dib7000m_config {
+       u8 dvbt_mode;
+       u8 output_mpeg2_in_188_bytes;
+       u8 hostbus_diversity;
+       u8 tuner_is_baseband;
+       u8 mobile_mode;
+       int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+       u8 agc_config_count;
+       struct dibx000_agc_config *agc;
+
+       struct dibx000_bandwidth_config *bw;
+
+#define DIB7000M_GPIO_DEFAULT_DIRECTIONS 0xffff
+       u16 gpio_dir;
+#define DIB7000M_GPIO_DEFAULT_VALUES     0x0000
+       u16 gpio_val;
+#define DIB7000M_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
+#define DIB7000M_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
+#define DIB7000M_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
+#define DIB7000M_GPIO_PWM_POS3(v)         (v & 0xf)
+#define DIB7000M_GPIO_DEFAULT_PWM_POS    0xffff
+       u16 gpio_pwm_pos;
+
+       u16 pwm_freq_div;
+
+       u8 quartz_direct;
+
+       u8 input_clk_is_div_2;
+
+       int (*agc_control) (struct dvb_frontend *, u8 before);
+};
+
+#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);
+
+/* TODO
+extern INT dib7000m_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+extern INT dib7000m_enable_vbg_voltage(struct dibDemod *demod);
+extern void dib7000m_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
+extern USHORT dib7000m_get_current_agc_global(struct dibDemod *demod);
+*/
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
new file mode 100644 (file)
index 0000000..0349a4b
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
+ *
+ * Copyright (C) 2005-6 DiBcom (http://www.dibcom.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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib7000p.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0)
+
+struct dib7000p_state {
+       struct dvb_frontend demod;
+    struct dib7000p_config cfg;
+
+       u8 i2c_addr;
+       struct i2c_adapter   *i2c_adap;
+
+       struct dibx000_i2c_master i2c_master;
+
+       u16 wbd_ref;
+
+       u8 current_band;
+       fe_bandwidth_t current_bandwidth;
+       struct dibx000_agc_config *current_agc;
+       u32 timf;
+
+       u16 gpio_dir;
+       u16 gpio_val;
+};
+
+enum dib7000p_power_mode {
+       DIB7000P_POWER_ALL = 0,
+       DIB7000P_POWER_INTERFACE_ONLY,
+};
+
+static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+{
+       u8 wb[2] = { reg >> 8, reg & 0xff };
+       u8 rb[2];
+       struct i2c_msg msg[2] = {
+               { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
+               { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+       };
+
+       if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d\n",reg);
+
+       return (rb[0] << 8) | rb[1];
+}
+
+static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+{
+       u8 b[4] = {
+               (reg >> 8) & 0xff, reg & 0xff,
+               (val >> 8) & 0xff, val & 0xff,
+       };
+       struct i2c_msg msg = {
+               .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+       };
+       return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
+{
+       int    ret = 0;
+       u16 outreg, fifo_threshold, smo_mode;
+
+       outreg = 0;
+       fifo_threshold = 1792;
+       smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
+
+       dprintk("-I-  Setting output mode for demod %p to %d\n",
+                       &state->demod, mode);
+
+       switch (mode) {
+               case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
+                       outreg = (1 << 10);  /* 0x0400 */
+                       break;
+               case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
+                       outreg = (1 << 10) | (1 << 6); /* 0x0440 */
+                       break;
+               case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
+                       outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
+                       break;
+               case OUTMODE_DIVERSITY:
+                       if (state->cfg.hostbus_diversity)
+                               outreg = (1 << 10) | (4 << 6); /* 0x0500 */
+                       else
+                               outreg = (1 << 11);
+                       break;
+               case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
+                       smo_mode |= (3 << 1);
+                       fifo_threshold = 512;
+                       outreg = (1 << 10) | (5 << 6);
+                       break;
+               case OUTMODE_HIGH_Z:  // disable
+                       outreg = 0;
+                       break;
+               default:
+                       dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+                       break;
+       }
+
+       if (state->cfg.output_mpeg2_in_188_bytes)
+               smo_mode |= (1 << 5) ;
+
+       ret |= dib7000p_write_word(state,  235, smo_mode);
+       ret |= dib7000p_write_word(state,  236, fifo_threshold); /* synchronous fread */
+       ret |= dib7000p_write_word(state, 1286, outreg);         /* P_Div_active */
+
+       return ret;
+}
+
+static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
+{
+       /* by default everything is powered off */
+       u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899  = 0x0003,
+               reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
+
+       /* now, depending on the requested mode, we power on */
+       switch (mode) {
+               /* power up everything in the demod */
+               case DIB7000P_POWER_ALL:
+                       reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
+                       break;
+               /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
+               case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
+                       reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
+                       break;
+/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
+       }
+
+       dib7000p_write_word(state,  774,  reg_774);
+       dib7000p_write_word(state,  775,  reg_775);
+       dib7000p_write_word(state,  776,  reg_776);
+       dib7000p_write_word(state,  899,  reg_899);
+       dib7000p_write_word(state, 1280, reg_1280);
+
+       return 0;
+}
+
+static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
+{
+       u16 reg_908 = dib7000p_read_word(state, 908),
+              reg_909 = dib7000p_read_word(state, 909);
+
+       switch (no) {
+               case DIBX000_SLOW_ADC_ON:
+                       reg_909 |= (1 << 1) | (1 << 0);
+                       dib7000p_write_word(state, 909, reg_909);
+                       reg_909 &= ~(1 << 1);
+                       break;
+
+               case DIBX000_SLOW_ADC_OFF:
+                       reg_909 |=  (1 << 1) | (1 << 0);
+                       break;
+
+               case DIBX000_ADC_ON:
+                       reg_908 &= 0x0fff;
+                       reg_909 &= 0x0003;
+                       break;
+
+               case DIBX000_ADC_OFF: // leave the VBG voltage on
+                       reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
+                       reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+                       break;
+
+               case DIBX000_VBG_ENABLE:
+                       reg_908 &= ~(1 << 15);
+                       break;
+
+               case DIBX000_VBG_DISABLE:
+                       reg_908 |= (1 << 15);
+                       break;
+
+               default:
+                       break;
+       }
+
+//     dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+
+       dib7000p_write_word(state, 908, reg_908);
+       dib7000p_write_word(state, 909, reg_909);
+}
+
+static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+{
+       struct dib7000p_state *state = demod->demodulator_priv;
+       u32 timf;
+
+       // store the current bandwidth for later use
+       state->current_bandwidth = BW_Idx;
+
+       if (state->timf == 0) {
+               dprintk("-D-  Using default timf\n");
+               timf = state->cfg.bw->timf;
+       } else {
+               dprintk("-D-  Using updated timf\n");
+               timf = state->timf;
+       }
+
+       timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
+
+       dprintk("timf: %d\n",timf);
+
+       dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
+       dib7000p_write_word(state, 24, (timf      ) & 0xffff);
+
+       return 0;
+}
+
+static int dib7000p_sad_calib(struct dib7000p_state *state)
+{
+/* internal */
+//     dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+       dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
+       dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
+
+       /* do the calibration */
+       dib7000p_write_word(state, 73, (1 << 0));
+       dib7000p_write_word(state, 73, (0 << 0));
+
+       msleep(1);
+
+       return 0;
+}
+
+static void dib7000p_reset_pll(struct dib7000p_state *state)
+{
+       struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+
+       dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
+       dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
+               (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+
+       dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
+       dib7000p_write_word(state, 19,  (bw->internal*1000       ) & 0xffff);
+       dib7000p_write_word(state, 21,  (bw->ifreq          >> 16) & 0xffff);
+       dib7000p_write_word(state, 22,  (bw->ifreq               ) & 0xffff);
+
+       dib7000p_write_word(state, 72, bw->sad_cfg);
+}
+
+static int dib7000p_reset_gpio(struct dib7000p_state *st)
+{
+       /* reset the GPIOs */
+       dprintk("-D-  gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+
+       dib7000p_write_word(st, 1029, st->gpio_dir);
+       dib7000p_write_word(st, 1030, st->gpio_val);
+
+       /* TODO 1031 is P_gpio_od */
+
+       dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
+
+       dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
+       return 0;
+}
+
+static int dib7000p_demod_reset(struct dib7000p_state *state)
+{
+       dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+
+       dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
+
+       /* restart all parts */
+       dib7000p_write_word(state,  770, 0xffff);
+       dib7000p_write_word(state,  771, 0xffff);
+       dib7000p_write_word(state,  772, 0x001f);
+       dib7000p_write_word(state,  898, 0x0003);
+       /* except i2c, sdio, gpio - control interfaces */
+       dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
+
+       dib7000p_write_word(state,  770, 0);
+       dib7000p_write_word(state,  771, 0);
+       dib7000p_write_word(state,  772, 0);
+       dib7000p_write_word(state,  898, 0);
+       dib7000p_write_word(state, 1280, 0);
+
+       /* default */
+       dib7000p_reset_pll(state);
+
+       if (dib7000p_reset_gpio(state) != 0)
+               dprintk("-E-  GPIO reset was not successful.\n");
+
+       if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+               dprintk("-E-  OUTPUT_MODE could not be resetted.\n");
+
+       /* unforce divstr regardless whether i2c enumeration was done or not */
+       dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+
+       dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
+       return 0;
+}
+
+static void dib7000p_restart_agc(struct dib7000p_state *state)
+{
+       // P_restart_iqc & P_restart_agc
+       dib7000p_write_word(state, 770, 0x0c00);
+       dib7000p_write_word(state, 770, 0x0000);
+}
+
+static void dib7000p_update_lna(struct dib7000p_state *state)
+{
+       int i;
+       u16 dyn_gain;
+
+       // when there is no LNA to program return immediatly
+       if (state->cfg.update_lna == NULL)
+               return;
+
+       for (i = 0; i < 5; i++) {
+               // read dyn_gain here (because it is demod-dependent and not tuner)
+               dyn_gain = dib7000p_read_word(state, 394);
+
+               if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+                       dib7000p_restart_agc(state);
+                       msleep(5);
+               } else
+                       break;
+       }
+}
+
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+       u16 tmp = 0;
+       tmp = dib7000p_read_word(state, 903);
+       dib7000p_write_word(state, 903, (tmp | 0x1));   //pwr-up pll
+       tmp = dib7000p_read_word(state, 900);
+       dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));     //use High freq clock
+}
+
+static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+{
+       u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
+       state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+       dib7000p_write_word(state, 23, (u16) (timf >> 16));
+       dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
+       dprintk("-D-  Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+}
+
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+{
+       u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+
+       /* nfft, guard, qam, alpha */
+       dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+       dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
+
+       /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
+       tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
+       if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
+               tmp |= (ch->vit_code_rate_hp << 1);
+       else
+               tmp |= (ch->vit_code_rate_lp << 1);
+       dib7000p_write_word(state, 208, tmp);
+
+       /* P_dvsy_sync_wait */
+       switch (ch->nfft) {
+               case 1: tmp = 256; break;
+               case 2: tmp = 128; break;
+               case 0:
+               default: tmp = 64; break;
+       }
+       tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
+       tmp <<= 4;
+
+       /* deactive the possibility of diversity reception if extended interleave */
+       /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+       if (ch->intlv_native || ch->nfft == 1)
+               tmp |= (1 << 2) | (2 << 0);
+       dib7000p_write_word(state, 207, tmp);
+
+       dib7000p_write_word(state, 26, 0x6680);   // timf(6xxx)
+       dib7000p_write_word(state, 29, 0x1273);   // isi inh1273 on1073
+       dib7000p_write_word(state, 32, 0x0003);   // pha_off_max(xxx3)
+       dib7000p_write_word(state, 33, 0x0005);   // sfreq(xxx5)
+
+       /* channel estimation fine configuration */
+       switch (ch->nqam) {
+               case 2:
+                       est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
+                       est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
+                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
+                       break;
+               case 1:
+                       est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
+                       est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
+                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
+                       est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
+                       break;
+               default:
+                       est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
+                       est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
+                       est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
+                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
+                       break;
+       }
+       for (tmp = 0; tmp < 4; tmp++)
+               dib7000p_write_word(state, 187 + tmp, est[tmp]);
+
+       // set power-up level: interf+analog+AGC
+       dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+       dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+       dib7000p_pll_clk_cfg(state);
+       msleep(7);
+
+       // AGC initialization
+       if (state->cfg.agc_control)
+               state->cfg.agc_control(&state->demod, 1);
+
+       dib7000p_restart_agc(state);
+
+       // wait AGC rough lock time
+       msleep(5);
+
+       dib7000p_update_lna(state);
+
+       // wait AGC accurate lock time
+       msleep(7);
+       if (state->cfg.agc_control)
+               state->cfg.agc_control(&state->demod, 0);
+}
+
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+       struct dib7000p_state *state = demod->demodulator_priv;
+       struct dibx000_ofdm_channel auto_ch;
+       u32 value;
+
+       INIT_OFDM_CHANNEL(&auto_ch);
+       auto_ch.RF_kHz           = ch->RF_kHz;
+       auto_ch.Bw               = ch->Bw;
+       auto_ch.nqam             = 2;
+       auto_ch.guard            = 0;
+       auto_ch.nfft             = 1;
+       auto_ch.vit_alpha        = 1;
+       auto_ch.vit_select_hp    = 1;
+       auto_ch.vit_code_rate_hp = 2;
+       auto_ch.vit_code_rate_lp = 3;
+       auto_ch.vit_hrch         = 0;
+       auto_ch.intlv_native     = 1;
+
+       dib7000p_set_channel(state, &auto_ch, 7);
+
+       // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
+       value = 30 * state->cfg.bw->internal;
+       dib7000p_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
+       dib7000p_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
+       value = 100 * state->cfg.bw->internal;
+       dib7000p_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
+       dib7000p_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
+       value = 500 * state->cfg.bw->internal;
+       dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
+       dib7000p_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
+
+       value = dib7000p_read_word(state, 0);
+       dib7000p_write_word(state, 0, (1 << 9) | value);
+       dib7000p_read_word(state, 1284);
+       dib7000p_write_word(state, 0, (u16) value);
+
+       return 0;
+}
+
+static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
+{
+       struct dib7000p_state *state = demod->demodulator_priv;
+       u16 irq_pending = dib7000p_read_word(state, 1284);
+
+       if (irq_pending & 0x1) // failed
+               return 1;
+
+       if (irq_pending & 0x2) // succeeded
+               return 2;
+
+       return 0; // still pending
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+       struct dib7000p_state *state = demod->demodulator_priv;
+       u16 tmp = 0;
+
+       if (ch != NULL)
+               dib7000p_set_channel(state, ch, 0);
+       else
+               return -EINVAL;
+
+       // restart demod
+       dib7000p_write_word(state, 770, 0x4000);
+       dib7000p_write_word(state, 770, 0x0000);
+       msleep(45);
+
+       /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
+       dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+
+       // never achieved a lock with that bandwidth so far - wait for osc-freq to update
+       if (state->timf == 0)
+               msleep(200);
+
+       /* offset loop parameters */
+
+       /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
+       tmp = (6 << 8) | 0x80;
+       switch (ch->nfft) {
+               case 0: tmp |= (7 << 12); break;
+               case 1: tmp |= (9 << 12); break;
+               case 2: tmp |= (8 << 12); break;
+       }
+       dib7000p_write_word(state, 26, tmp);  /* timf_a(6xxx) */
+
+       /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
+       tmp = (0 << 4);
+       switch (ch->nfft) {
+               case 0: tmp |= 0x6; break;
+               case 1: tmp |= 0x8; break;
+               case 2: tmp |= 0x7; break;
+       }
+       dib7000p_write_word(state, 32,  tmp);
+
+       /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
+       tmp = (0 << 4);
+       switch (ch->nfft) {
+               case 0: tmp |= 0x6; break;
+               case 1: tmp |= 0x8; break;
+               case 2: tmp |= 0x7; break;
+       }
+       dib7000p_write_word(state, 33,  tmp);
+
+       tmp = dib7000p_read_word(state,509);
+       if (!((tmp >> 6) & 0x1)) {
+               /* restart the fec */
+               tmp = dib7000p_read_word(state,771);
+               dib7000p_write_word(state, 771, tmp | (1 << 1));
+               dib7000p_write_word(state, 771, tmp);
+               msleep(10);
+               tmp = dib7000p_read_word(state,509);
+       }
+
+       // we achieved a lock - it's time to update the osc freq
+       if ((tmp >> 6) & 0x1)
+               dib7000p_update_timf_freq(state);
+
+       return 0;
+}
+
+static int dib7000p_init(struct dvb_frontend *demod)
+{
+       struct dibx000_agc_config *agc;
+       struct dib7000p_state *state = demod->demodulator_priv;
+       int ret = 0;
+
+       // Demodulator default configuration
+       agc = state->cfg.agc;
+
+       dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+       dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+
+       /* AGC */
+       ret |= dib7000p_write_word(state, 75 ,  agc->setup );
+       ret |= dib7000p_write_word(state, 76 ,  agc->inv_gain );
+       ret |= dib7000p_write_word(state, 77 ,  agc->time_stabiliz );
+       ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+       // Demod AGC loop configuration
+       ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+       ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6)  | agc->beta_exp);
+
+       /* AGC continued */
+       dprintk("-D-  WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+               state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+       if (state->wbd_ref != 0)
+               ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+       else
+               ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+       ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
+
+       ret |= dib7000p_write_word(state, 107,  agc->agc1_max);
+       ret |= dib7000p_write_word(state, 108,  agc->agc1_min);
+       ret |= dib7000p_write_word(state, 109,  agc->agc2_max);
+       ret |= dib7000p_write_word(state, 110,  agc->agc2_min);
+       ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
+       ret |= dib7000p_write_word(state, 112,  agc->agc1_pt3);
+       ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+       ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+       ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+       /* disable power smoothing */
+       ret |= dib7000p_write_word(state, 145, 0);
+       ret |= dib7000p_write_word(state, 146, 0);
+       ret |= dib7000p_write_word(state, 147, 0);
+       ret |= dib7000p_write_word(state, 148, 0);
+       ret |= dib7000p_write_word(state, 149, 0);
+       ret |= dib7000p_write_word(state, 150, 0);
+       ret |= dib7000p_write_word(state, 151, 0);
+       ret |= dib7000p_write_word(state, 152, 0);
+
+       // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+       ret |= dib7000p_write_word(state, 26 ,0x6680);
+
+       // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+       ret |= dib7000p_write_word(state, 142,0x0410);
+       // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+       ret |= dib7000p_write_word(state, 154,1 << 13);
+       // P_pha3_thres, default 0x3000
+       ret |= dib7000p_write_word(state, 168,0x0ccd);
+       // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+       //ret |= dib7000p_write_word(state, 169,0x0010);
+       // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+       ret |= dib7000p_write_word(state, 183,0x200f);
+       // P_adp_regul_cnt=573, default: 410
+       ret |= dib7000p_write_word(state, 187,0x023d);
+       // P_adp_noise_cnt=
+       ret |= dib7000p_write_word(state, 188,0x00a4);
+       // P_adp_regul_ext
+       ret |= dib7000p_write_word(state, 189,0x00a4);
+       // P_adp_noise_ext
+       ret |= dib7000p_write_word(state, 190,0x7ff0);
+       // P_adp_fil
+       ret |= dib7000p_write_word(state, 191,0x3ccc);
+
+       ret |= dib7000p_write_word(state, 222,0x0010);
+       // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+       ret |= dib7000p_write_word(state, 235,0x0062);
+
+       // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+       if(state->cfg.tuner_is_baseband)
+               ret |= dib7000p_write_word(state, 36,0x0755);
+       else
+               ret |= dib7000p_write_word(state, 36,0x1f55);
+
+       // auto search configuration
+       ret |= dib7000p_write_word(state, 2  ,0x0004);
+       ret |= dib7000p_write_word(state, 3  ,0x1000);
+
+       /* Equal Lock */
+       ret |= dib7000p_write_word(state, 4   ,0x0814);
+
+       ret |= dib7000p_write_word(state, 6  ,0x001b);
+       ret |= dib7000p_write_word(state, 7  ,0x7740);
+       ret |= dib7000p_write_word(state, 8  ,0x005b);
+       ret |= dib7000p_write_word(state, 9  ,0x8d80);
+       ret |= dib7000p_write_word(state, 10 ,0x01c9);
+       ret |= dib7000p_write_word(state, 11 ,0xc380);
+       ret |= dib7000p_write_word(state, 12 ,0x0000);
+       ret |= dib7000p_write_word(state, 13 ,0x0080);
+       ret |= dib7000p_write_word(state, 14 ,0x0000);
+       ret |= dib7000p_write_word(state, 15 ,0x0090);
+       ret |= dib7000p_write_word(state, 16 ,0x0001);
+       ret |= dib7000p_write_word(state, 17 ,0xd4c0);
+
+       // P_clk_cfg1
+       ret |= dib7000p_write_word(state, 901, 0x0006);
+
+       // P_divclksel=3 P_divbitsel=1
+       ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
+
+       // Tuner IO bank: max drive (14mA) + divout pads max drive
+       ret |= dib7000p_write_word(state, 905, 0x2c8e);
+
+       ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+       dib7000p_sad_calib(state);
+
+       return ret;
+}
+
+static int dib7000p_sleep(struct dvb_frontend *demod)
+{
+       struct dib7000p_state *state = demod->demodulator_priv;
+       return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+}
+
+static int dib7000p_identify(struct dib7000p_state *st)
+{
+       u16 value;
+       dprintk("-I-  DiB7000PC: checking demod on I2C address: %d (%x)\n",
+               st->i2c_addr, st->i2c_addr);
+
+       if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
+               dprintk("-E-  DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+               return -EREMOTEIO;
+       }
+
+       if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
+               dprintk("-E-  DiB7000PC: wrong Device ID (%x)\n",value);
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+
+static int dib7000p_get_frontend(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *fep)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 tps = dib7000p_read_word(state,463);
+
+       fep->inversion = INVERSION_AUTO;
+
+       fep->u.ofdm.bandwidth = state->current_bandwidth;
+
+       switch ((tps >> 8) & 0x3) {
+               case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+               case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+               /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+       }
+
+       switch (tps & 0x3) {
+               case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
+               case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
+               case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
+               case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+       }
+
+       switch ((tps >> 14) & 0x3) {
+               case 0: fep->u.ofdm.constellation = QPSK; break;
+               case 1: fep->u.ofdm.constellation = QAM_16; break;
+               case 2:
+               default: fep->u.ofdm.constellation = QAM_64; break;
+       }
+
+       /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+       /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
+
+       fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       switch ((tps >> 5) & 0x7) {
+               case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
+               case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
+               case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
+               case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+               case 7:
+               default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+
+       }
+
+       switch ((tps >> 2) & 0x7) {
+               case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
+               case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
+               case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
+               case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+               case 7:
+               default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+       }
+
+       /* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
+
+       return 0;
+}
+
+static int dib7000p_set_frontend(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *fep)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       struct dibx000_ofdm_channel ch;
+
+       INIT_OFDM_CHANNEL(&ch);
+       FEP2DIB(fep,&ch);
+
+       state->current_bandwidth = fep->u.ofdm.bandwidth;
+       dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, fep);
+
+       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
+               fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
+               fep->u.ofdm.constellation     == QAM_AUTO ||
+               fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+               int i = 800, found;
+
+               dib7000p_autosearch_start(fe, &ch);
+               do {
+                       msleep(1);
+                       found = dib7000p_autosearch_is_irq(fe);
+               } while (found == 0 && i--);
+
+               dprintk("autosearch returns: %d\n",found);
+               if (found == 0 || found == 1)
+                       return 0; // no channel found
+
+               dib7000p_get_frontend(fe, fep);
+               FEP2DIB(fep, &ch);
+       }
+
+       /* make this a config parameter */
+       dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+       return dib7000p_tune(fe, &ch);
+}
+
+static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 lock = dib7000p_read_word(state, 509);
+
+       *stat = 0;
+
+       if (lock & 0x8000)
+               *stat |= FE_HAS_SIGNAL;
+       if (lock & 0x3000)
+               *stat |= FE_HAS_CARRIER;
+       if (lock & 0x0100)
+               *stat |= FE_HAS_VITERBI;
+       if (lock & 0x0010)
+               *stat |= FE_HAS_SYNC;
+       if (lock & 0x0008)
+               *stat |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
+       return 0;
+}
+
+static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       *unc = dib7000p_read_word(state, 506);
+       return 0;
+}
+
+static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 val = dib7000p_read_word(state, 394);
+       *strength = 65535 - val;
+       return 0;
+}
+
+static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       *snr = 0x0000;
+       return 0;
+}
+
+static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 1000;
+       return 0;
+}
+
+static void dib7000p_release(struct dvb_frontend *demod)
+{
+       struct dib7000p_state *st = demod->demodulator_priv;
+       dibx000_exit_i2c_master(&st->i2c_master);
+       kfree(st);
+}
+
+int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+{
+       u8 tx[2], rx[2];
+       struct i2c_msg msg[2] = {
+               { .addr = 18 >> 1, .flags = 0,        .buf = tx, .len = 2 },
+               { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
+       };
+
+       tx[0] = 0x03;
+       tx[1] = 0x00;
+
+       if (i2c_transfer(i2c_adap, msg, 2) == 2)
+               if (rx[0] == 0x01 && rx[1] == 0xb3) {
+                       dprintk("-D-  DiB7000PC detected\n");
+                       return 1;
+               }
+
+       msg[0].addr = msg[1].addr = 0x40;
+
+       if (i2c_transfer(i2c_adap, msg, 2) == 2)
+               if (rx[0] == 0x01 && rx[1] == 0xb3) {
+                       dprintk("-D-  DiB7000PC detected\n");
+                       return 1;
+               }
+
+       dprintk("-D-  DiB7000PC not detected\n");
+       return 0;
+}
+EXPORT_SYMBOL(dib7000pc_detection);
+
+struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+{
+       struct dib7000p_state *st = demod->demodulator_priv;
+       return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib7000p_get_i2c_master);
+
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+{
+       struct dib7000p_state st = { .i2c_adap = i2c };
+       int k = 0;
+       u8 new_addr = 0;
+
+       for (k = no_of_demods-1; k >= 0; k--) {
+               st.cfg = cfg[k];
+
+               /* designated i2c address */
+               new_addr          = (0x40 + k) << 1;
+               st.i2c_addr = new_addr;
+               if (dib7000p_identify(&st) != 0) {
+                       st.i2c_addr = default_addr;
+                       if (dib7000p_identify(&st) != 0) {
+                               dprintk("DiB7000P #%d: not identified\n", k);
+                               return -EIO;
+                       }
+               }
+
+               /* start diversity to pull_down div_str - just for i2c-enumeration */
+               dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
+
+               /* set new i2c address and force divstart */
+               dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
+
+               dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+       }
+
+       for (k = 0; k < no_of_demods; k++) {
+               st.cfg = cfg[k];
+               st.i2c_addr = (0x40 + k) << 1;
+
+               // unforce divstr
+               dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
+
+               /* deactivate div - it was just for i2c-enumeration */
+               dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(dib7000p_i2c_enumeration);
+
+static struct dvb_frontend_ops dib7000p_ops;
+struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+{
+       struct dvb_frontend *demod;
+       struct dib7000p_state *st;
+       st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
+       if (st == NULL)
+               return NULL;
+
+       memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
+       st->i2c_adap = i2c_adap;
+       st->i2c_addr = i2c_addr;
+       st->gpio_val = cfg->gpio_val;
+       st->gpio_dir = cfg->gpio_dir;
+
+       demod                   = &st->demod;
+       demod->demodulator_priv = st;
+       memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
+
+       if (dib7000p_identify(st) != 0)
+               goto error;
+
+       dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
+
+       dib7000p_demod_reset(st);
+
+       return demod;
+
+error:
+       kfree(st);
+       return NULL;
+}
+EXPORT_SYMBOL(dib7000p_attach);
+
+static struct dvb_frontend_ops dib7000p_ops = {
+       .info = {
+               .name = "DiBcom 7000PC",
+               .type = FE_OFDM,
+               .frequency_min      = 44250000,
+               .frequency_max      = 867250000,
+               .frequency_stepsize = 62500,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_RECOVER |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release              = dib7000p_release,
+
+       .init                 = dib7000p_init,
+       .sleep                = dib7000p_sleep,
+
+       .set_frontend         = dib7000p_set_frontend,
+       .get_tune_settings    = dib7000p_fe_get_tune_settings,
+       .get_frontend         = dib7000p_get_frontend,
+
+       .read_status          = dib7000p_read_status,
+       .read_ber             = dib7000p_read_ber,
+       .read_signal_strength = dib7000p_read_signal_strength,
+       .read_snr             = dib7000p_read_snr,
+       .read_ucblocks        = dib7000p_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
new file mode 100644 (file)
index 0000000..79465cf
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DIB7000P_H
+#define DIB7000P_H
+
+#include "dibx000_common.h"
+
+struct dib7000p_config {
+       u8 output_mpeg2_in_188_bytes;
+       u8 hostbus_diversity;
+       u8 tuner_is_baseband;
+       int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+
+       struct dibx000_agc_config *agc;
+       struct dibx000_bandwidth_config *bw;
+
+#define DIB7000P_GPIO_DEFAULT_DIRECTIONS 0xffff
+       u16 gpio_dir;
+#define DIB7000P_GPIO_DEFAULT_VALUES     0x0000
+       u16 gpio_val;
+#define DIB7000P_GPIO_PWM_POS0(v)        ((v & 0xf) << 12)
+#define DIB7000P_GPIO_PWM_POS1(v)        ((v & 0xf) << 8 )
+#define DIB7000P_GPIO_PWM_POS2(v)        ((v & 0xf) << 4 )
+#define DIB7000P_GPIO_PWM_POS3(v)         (v & 0xf)
+#define DIB7000P_GPIO_DEFAULT_PWM_POS    0xffff
+       u16 gpio_pwm_pos;
+
+       u16 pwm_freq_div;
+
+       u8 quartz_direct;
+
+       int (*agc_control) (struct dvb_frontend *, u8 before);
+};
+
+#define DEFAULT_DIB7000P_I2C_ADDRESS 18
+
+extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
+
+/* TODO
+extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
+extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
+extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
+extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
+*/
+
+#endif
index bb0c65f8aee88fa0cb7050699808f2795240ac70..a1df604366c37251200771362ffe7c331fdb8196 100644 (file)
@@ -32,6 +32,13 @@ extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
 #define BAND_LBAND 0x01
 #define BAND_UHF   0x02
 #define BAND_VHF   0x04
+#define BAND_SBAND 0x08
+#define BAND_FM           0x10
+
+#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \
+                                                                       (freq_kHz) <= 250000 ? BAND_VHF : \
+                                                                       (freq_kHz) <= 863000 ? BAND_UHF : \
+                                                                       (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND )
 
 struct dibx000_agc_config {
        /* defines the capabilities of this AGC-setting - using the BAND_-defines*/
@@ -129,6 +136,7 @@ enum dibx000_adc_states {
 
 /* I hope I can get rid of the following kludge in the near future */
 struct dibx000_ofdm_channel {
+       u32 RF_kHz;
        u8  Bw;
        s16 nfft;
        s16 guard;
@@ -138,9 +146,11 @@ struct dibx000_ofdm_channel {
        s16 vit_alpha;
        s16 vit_code_rate_hp;
        s16 vit_code_rate_lp;
+       u8  intlv_native;
 };
 
 #define FEP2DIB(fep,ch) \
+       (ch)->RF_kHz           = (fep)->frequency / 1000; \
        (ch)->Bw               = (fep)->u.ofdm.bandwidth; \
        (ch)->nfft             = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
        (ch)->guard            = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
@@ -149,7 +159,8 @@ struct dibx000_ofdm_channel {
        (ch)->vit_select_hp    = 1; \
        (ch)->vit_alpha        = 1; \
        (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
-       (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP;
+       (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
+       (ch)->intlv_native     = 1;
 
 #define INIT_OFDM_CHANNEL(ch) do {\
        (ch)->Bw               = 0;  \
index b7e7108ee5b3cadd0e82c562a1264575a9e9a093..62de760c844ff09683589a77389c879e24cc1ee6 100644 (file)
@@ -472,14 +472,14 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
                printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
                       desc->name, div, buf[0], buf[1], buf[2], buf[3]);
 
-       return 0;
+       // calculate the frequency we set it to
+       return (div * desc->entries[i].stepsize) - desc->entries[i].offset;
 }
 EXPORT_SYMBOL(dvb_pll_configure);
 
 static int dvb_pll_release(struct dvb_frontend *fe)
 {
-       if (fe->tuner_priv)
-               kfree(fe->tuner_priv);
+       kfree(fe->tuner_priv);
        fe->tuner_priv = NULL;
        return 0;
 }
@@ -489,7 +489,8 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
        struct dvb_pll_priv *priv = fe->tuner_priv;
        u8 buf[4];
        struct i2c_msg msg =
-               { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+               { .addr = priv->pll_i2c_address, .flags = 0,
+                 .buf = buf, .len = sizeof(buf) };
        int i;
        int result;
 
@@ -517,16 +518,16 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvb_pll_set_params(struct dvb_frontend *fe,
+                             struct dvb_frontend_parameters *params)
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        u8 buf[4];
        struct i2c_msg msg =
-               { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+               { .addr = priv->pll_i2c_address, .flags = 0,
+                 .buf = buf, .len = sizeof(buf) };
        int result;
-       u32 div;
-       int i;
-       u32 bandwidth = 0;
+       u32 bandwidth = 0, frequency = 0;
 
        if (priv->i2c == NULL)
                return -EINVAL;
@@ -536,8 +537,11 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
                bandwidth = params->u.ofdm.bandwidth;
        }
 
-       if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf,
+                                       params->frequency, bandwidth)) < 0)
                return result;
+       else
+               frequency = result;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -545,26 +549,19 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
                return result;
        }
 
-       // calculate the frequency we set it to
-       for (i = 0; i < priv->pll_desc->count; i++) {
-               if (params->frequency > priv->pll_desc->entries[i].limit)
-                       continue;
-               break;
-       }
-       div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
-       priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+       priv->frequency = frequency;
        priv->bandwidth = bandwidth;
 
        return 0;
 }
 
-static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+static int dvb_pll_calc_regs(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *params,
+                            u8 *buf, int buf_len)
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        int result;
-       u32 div;
-       int i;
-       u32 bandwidth = 0;
+       u32 bandwidth = 0, frequency = 0;
 
        if (buf_len < 5)
                return -EINVAL;
@@ -574,18 +571,15 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parame
                bandwidth = params->u.ofdm.bandwidth;
        }
 
-       if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+       if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
+                                       params->frequency, bandwidth)) < 0)
                return result;
+       else
+               frequency = result;
+
        buf[0] = priv->pll_i2c_address;
 
-       // calculate the frequency we set it to
-       for (i = 0; i < priv->pll_desc->count; i++) {
-               if (params->frequency > priv->pll_desc->entries[i].limit)
-                       continue;
-               break;
-       }
-       div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
-       priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+       priv->frequency = frequency;
        priv->bandwidth = bandwidth;
 
        return 5;
@@ -614,10 +608,13 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
        .get_bandwidth = dvb_pll_get_bandwidth,
 };
 
-struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
+                                   struct i2c_adapter *i2c,
+                                   struct dvb_pll_desc *desc)
 {
        u8 b1 [] = { 0 };
-       struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
+       struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
+                              .buf = b1, .len = 1 };
        struct dvb_pll_priv *priv = NULL;
        int ret;
 
@@ -640,7 +637,9 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struc
        priv->i2c = i2c;
        priv->pll_desc = desc;
 
-       memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+       memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
        strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
        fe->ops.tuner_ops.info.frequency_min = desc->min;
        fe->ops.tuner_ops.info.frequency_min = desc->max;
index ed5ac5a361ae12da3c65a850f33bbe67f48f3f63..681186a5e5ebeeb93bae197f15325b372fee02e7 100644 (file)
@@ -48,7 +48,7 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
 extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-                     u32 freq, int bandwidth);
+                            u32 freq, int bandwidth);
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
@@ -59,6 +59,9 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
  * @param desc dvb_pll_desc to use.
  * @return Frontend pointer on success, NULL on failure
  */
-extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+                                          int pll_addr,
+                                          struct i2c_adapter *i2c,
+                                          struct dvb_pll_desc *desc);
 
 #endif
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
deleted file mode 100644 (file)
index 754d51d..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
- *
- *  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 _LG_H06XF_H_
-#define _LG_H06XF_H_
-#include "dvb-pll.h"
-
-static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
-                    struct dvb_frontend_parameters* params)
-{
-       u8 buf[4];
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0,
-                              .buf = buf, .len = sizeof(buf) };
-       int err;
-
-       dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "lg_h06xf: %s error "
-                       "(addr %02x <- %02x, err = %i)\n",
-                       __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       /* Set the Auxiliary Byte. */
-       buf[0] = buf[2];
-       buf[0] &= ~0x20;
-       buf[0] |= 0x18;
-       buf[1] = 0x50;
-       msg.len = 2;
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "lg_h06xf: %s error "
-                       "(addr %02x <- %02x, err = %i)\n",
-                       __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-#endif
index 9a354708bd20a24f5dc946e05a1f25972a5899a7..68aad0f6519f7ab6f3af6445dd2e8249be5eb6dc 100644 (file)
@@ -31,9 +31,6 @@
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *   pcHDTV HD5500
  *
- * TODO:
- * signal strength always returns 0.
- *
  */
 
 #include <linux/kernel.h>
 #include <asm/byteorder.h>
 
 #include "dvb_frontend.h"
+#include "dvb_math.h"
 #include "lgdt330x_priv.h"
 #include "lgdt330x.h"
 
+/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
+/* #define USE_EQMSE */
+
 static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
@@ -68,6 +69,7 @@ struct lgdt330x_state
 
        /* Demodulator private data */
        fe_modulation_t current_modulation;
+       u32 snr; /* Result of last SNR calculation */
 
        /* Tuner private data */
        u32 current_frequency;
@@ -302,10 +304,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
        static u8 lgdt3303_8vsb_44_data[] = {
                0x04, 0x00,
                0x0d, 0x40,
-       0x0e, 0x87,
-       0x0f, 0x8e,
-       0x10, 0x01,
-       0x47, 0x8b };
+               0x0e, 0x87,
+               0x0f, 0x8e,
+               0x10, 0x01,
+               0x47, 0x8b };
 
        /*
         * Array of byte pairs <address, value>
@@ -435,9 +437,6 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
                /* Test signal does not exist flag */
                /* as well as the AGC lock flag.   */
                *status |= FE_HAS_SIGNAL;
-       } else {
-               /* Without a signal all other status bits are meaningless */
-               return 0;
        }
 
        /*
@@ -500,9 +499,6 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
                /* Test input signal does not exist flag */
                /* as well as the AGC lock flag.   */
                *status |= FE_HAS_SIGNAL;
-       } else {
-               /* Without a signal all other status bits are meaningless */
-               return 0;
        }
 
        /* Carrier Recovery Lock Status Register */
@@ -543,151 +539,150 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+/* Calculate SNR estimation (scaled by 2^24)
+
+   8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM
+   equations from LGDT3303 datasheet.  VSB is the same between the '02
+   and '03, so maybe QAM is too?  Perhaps someone with a newer datasheet
+   that has QAM information could verify?
+
+   For 8-VSB: (two ways, take your pick)
+   LGDT3302:
+     SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE)
+   LGDT3303:
+     SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE)
+   LGDT3302 & LGDT3303:
+     SNR_PT = 10 * log10(25 * 32^2 / PT_MSE)  (we use this one)
+   For 64-QAM:
+     SNR    = 10 * log10( 688128   / MSEQAM)
+   For 256-QAM:
+     SNR    = 10 * log10( 696320   / MSEQAM)
+
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - intlog10(MSE))
+   Where for 256-QAM, c = log10(696320) * 2^24, and so on. */
+
+static u32 calculate_snr(u32 mse, u32 c)
 {
-       /* not directly available. */
-       *strength = 0;
-       return 0;
+       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 lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-#ifdef SNR_IN_DB
-       /*
-        * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
-        * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
-        * respectively. The following tables are built on these formulas.
-        * The usual definition is SNR = 20 log10(signal/noise)
-        * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
-        *
-        * This table is a an ordered list of noise values computed by the
-        * formula from the spec sheet such that the index into the table
-        * starting at 43 or 45 is the SNR value in db. There are duplicate noise
-        * value entries at the beginning because the SNR varies more than
-        * 1 db for a change of 1 digit in noise at very small values of noise.
-        *
-        * Examples from SNR_EQ table:
-        * noise SNR
-        *   0    43
-        *   1    42
-        *   2    39
-        *   3    37
-        *   4    36
-        *   5    35
-        *   6    34
-        *   7    33
-        *   8    33
-        *   9    32
-        *   10   32
-        *   11   31
-        *   12   31
-        *   13   30
-        */
-
-       static const u32 SNR_EQ[] =
-               { 1,     2,      2,      2, 3,      3,      4,     4,     5,     7,
-                 9,     11,     13,     17, 21,     26,     33,    41,    52,    65,
-                 81,    102,    129,    162, 204,    257,    323,   406,   511,   644,
-                 810,   1020,   1284,   1616, 2035,   2561,   3224,  4059,  5110,  6433,
-                 8098,  10195,  12835,  16158, 20341,  25608,  32238, 40585, 51094, 64323,
-                 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
-               };
-
-       static const u32 SNR_PH[] =
-               { 1,     2,      2,      2,      3,      3,     4,     5,     6,     8,
-                 10,    12,     15,     19,     23,     29, 37,    46,    58,    73,
-                 91,    115,    144,    182,    229,    288, 362,   456,   574,   722,
-                 909,   1144,   1440,   1813,   2282,   2873, 3617,  4553,  5732,  7216,
-                 9084,  11436,  14396,  18124,  22817,  28724,  36161, 45524, 57312, 72151,
-                 90833, 114351, 143960, 181235, 228161, 0x080000
-               };
-
-       static u8 buf[5];/* read data buffer */
-       static u32 noise;   /* noise value */
-       static u32 snr_db;  /* index into SNR_EQ[] */
        struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+       u8 buf[5];      /* read data buffer */
+       u32 noise;      /* noise value */
+       u32 c;          /* per-modulation SNR calculation constant */
 
-       /* read both equalizer and phase tracker noise data */
-       i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
-
-       if (state->current_modulation == VSB_8) {
-               /* Equalizer Mean-Square Error Register for VSB */
+       switch(state->current_modulation) {
+       case VSB_8:
+               i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+               /* Use Equalizer Mean-Square Error Register */
+               /* SNR for ranges from -15.61 to +41.58 */
                noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
-
-               /*
-                * Look up noise value in table.
-                * A better search algorithm could be used...
-                * watch out there are duplicate entries.
-                */
-               for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
-                       if (noise < SNR_EQ[snr_db]) {
-                               *snr = 43 - snr_db;
-                               break;
-                       }
-               }
-       } else {
-               /* Phase Tracker Mean-Square Error Register for QAM */
-               noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
-
-               /* Look up noise value in table. */
-               for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
-                       if (noise < SNR_PH[snr_db]) {
-                               *snr = 45 - snr_db;
-                               break;
-                       }
-               }
-       }
+               c = 69765745; /* log10(25*24^2)*2^24 */
 #else
-       /* Return the raw noise value */
-       static u8 buf[5];/* read data buffer */
-       static u32 noise;   /* noise value */
-       struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-
-       /* read both equalizer and pase tracker noise data */
-       i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
-
-       if (state->current_modulation == VSB_8) {
-               /* Phase Tracker Mean-Square Error Register for VSB */
+               /* Use Phase Tracker Mean-Square Error Register */
+               /* SNR for ranges from -13.11 to +44.08 */
                noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
-       } else {
-
-               /* Carrier Recovery Mean-Square Error for QAM */
-               i2c_read_demod_bytes(state, 0x1a, buf, 2);
+               c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+               break;
+       case QAM_64:
+       case QAM_256:
+               i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
                noise = ((buf[0] & 3) << 8) | buf[1];
+               c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+               /* log10(688128)*2^24 and log10(696320)*2^24 */
+               break;
+       default:
+               printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+                      __FUNCTION__);
+               return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
        }
 
-       /* Small values for noise mean signal is better so invert noise */
-       *snr = ~noise;
-#endif
+       state->snr = calculate_snr(noise, c);
+       *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
 
-       dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+       dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+               state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
        return 0;
 }
 
 static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-       /* Return the raw noise value */
-       static u8 buf[5];/* read data buffer */
-       static u32 noise;   /* noise value */
        struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+       u8 buf[5];      /* read data buffer */
+       u32 noise;      /* noise value */
+       u32 c;          /* per-modulation SNR calculation constant */
 
-       if (state->current_modulation == VSB_8) {
-
-               i2c_read_demod_bytes(state, 0x6e, buf, 5);
-               /* Phase Tracker Mean-Square Error Register for VSB */
+       switch(state->current_modulation) {
+       case VSB_8:
+               i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5);
+#ifdef USE_EQMSE
+               /* Use Equalizer Mean-Square Error Register */
+               /* SNR for ranges from -16.12 to +44.08 */
+               noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
+               c = 73957994; /* log10(25*32^2)*2^24 */
+#else
+               /* Use Phase Tracker Mean-Square Error Register */
+               /* SNR for ranges from -13.11 to +44.08 */
                noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
-       } else {
-
-               /* Carrier Recovery Mean-Square Error for QAM */
-               i2c_read_demod_bytes(state, 0x1a, buf, 2);
+               c = 73957994; /* log10(25*32^2)*2^24 */
+#endif
+               break;
+       case QAM_64:
+       case QAM_256:
+               i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2);
                noise = (buf[0] << 8) | buf[1];
+               c = state->current_modulation == QAM_64 ? 97939837 : 98026066;
+               /* log10(688128)*2^24 and log10(696320)*2^24 */
+               break;
+       default:
+               printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n",
+                      __FUNCTION__);
+               return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */
        }
 
-       /* Small values for noise mean signal is better so invert noise */
-       *snr = ~noise;
+       state->snr = calculate_snr(noise, c);
+       *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
+
+       dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+               state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16);
+
+       return 0;
+}
+
+static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       /* 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 lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+       u16 snr;
+       int ret;
 
-       dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+       ret = fe->ops.read_snr(fe, &snr);
+       if (ret != 0)
+               return ret;
+       /* 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;
 
        return 0;
 }
index 59b7c5b9012d6e89e4ac688eb3bfb5e3783a2d55..38c76695abfe0d19904c9c78b1283fcc5ff0d198 100644 (file)
@@ -51,14 +51,19 @@ enum I2C_REG {
        AGC_RFIF_ACC2= 0x3b,
        AGC_STATUS= 0x3f,
        SYNC_STATUS_VSB= 0x43,
-       EQPH_ERR0= 0x47,
-       EQ_ERR1= 0x48,
-       EQ_ERR2= 0x49,
-       PH_ERR1= 0x4a,
-       PH_ERR2= 0x4b,
        DEMUX_CONTROL= 0x66,
+       LGDT3302_EQPH_ERR0= 0x47,
+       LGDT3302_EQ_ERR1= 0x48,
+       LGDT3302_EQ_ERR2= 0x49,
+       LGDT3302_PH_ERR1= 0x4a,
+       LGDT3302_PH_ERR2= 0x4b,
        LGDT3302_PACKET_ERR_COUNTER1= 0x6a,
        LGDT3302_PACKET_ERR_COUNTER2= 0x6b,
+       LGDT3303_EQPH_ERR0= 0x6e,
+       LGDT3303_EQ_ERR1= 0x6f,
+       LGDT3303_EQ_ERR2= 0x70,
+       LGDT3303_PH_ERR1= 0x71,
+       LGDT3303_PH_ERR2= 0x72,
        LGDT3303_PACKET_ERR_COUNTER1= 0x8b,
        LGDT3303_PACKET_ERR_COUNTER2= 0x8c,
 };
diff --git a/drivers/media/dvb/frontends/lgh06xf.c b/drivers/media/dvb/frontends/lgh06xf.c
new file mode 100644 (file)
index 0000000..2202d0c
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF
+ *
+ *  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 "dvb-pll.h"
+#include "lgh06xf.h"
+
+#define LG_H06XF_PLL_I2C_ADDR 0x61
+
+struct lgh06xf_priv {
+       struct i2c_adapter *i2c;
+       u32 frequency;
+};
+
+static int lgh06xf_release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static int lgh06xf_set_params(struct dvb_frontend* fe,
+                             struct dvb_frontend_parameters* params)
+{
+       struct lgh06xf_priv *priv = fe->tuner_priv;
+       u8 buf[4];
+       struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0,
+                              .buf = buf, .len = sizeof(buf) };
+       u32 frequency;
+       int result;
+
+       if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf,
+                                       params->frequency, 0)) < 0)
+               return result;
+       else
+               frequency = result;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lgh06xf: %s error "
+                      "(addr %02x <- %02x, result = %i)\n",
+                      __FUNCTION__, buf[0], buf[1], result);
+               if (result < 0)
+                       return result;
+               else
+                       return -EREMOTEIO;
+       }
+
+       /* Set the Auxiliary Byte. */
+       buf[0] = buf[2];
+       buf[0] &= ~0x20;
+       buf[0] |= 0x18;
+       buf[1] = 0x50;
+       msg.len = 2;
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lgh06xf: %s error "
+                      "(addr %02x <- %02x, result = %i)\n",
+                      __FUNCTION__, buf[0], buf[1], result);
+               if (result < 0)
+                       return result;
+               else
+                       return -EREMOTEIO;
+       }
+
+       priv->frequency = frequency;
+
+       return 0;
+}
+
+static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct lgh06xf_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static struct dvb_tuner_ops lgh06xf_tuner_ops = {
+       .release       = lgh06xf_release,
+       .set_params    = lgh06xf_set_params,
+       .get_frequency = lgh06xf_get_frequency,
+};
+
+struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c)
+{
+       struct lgh06xf_priv *priv = NULL;
+
+       priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return NULL;
+
+       priv->i2c = i2c;
+
+       memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops,
+              sizeof(struct dvb_tuner_ops));
+
+       strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name,
+               sizeof(fe->ops.tuner_ops.info.name));
+
+       fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min;
+       fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max;
+
+       fe->tuner_priv = priv;
+       return fe;
+}
+
+EXPORT_SYMBOL(lgh06xf_attach);
+
+MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support");
+MODULE_AUTHOR("Michael Krufky");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgh06xf.h b/drivers/media/dvb/frontends/lgh06xf.h
new file mode 100644 (file)
index 0000000..510b4be
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ *  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 _LGH06XF_H_
+#define _LGH06XF_H_
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
+                                           struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_LGH06XF */
+
+#endif /* _LGH06XF_H_ */
index d20ab30c1e8341d37af3600a41d97bb1ff02a7c1..5a3a6e53cda25877b6e97bc28f310a05688cab3c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
+#include "dvb_math.h"
 #include "dvb_frontend.h"
 #include "dvb-pll.h"
 #include "or51132.h"
@@ -62,6 +63,7 @@ struct or51132_state
 
        /* Demodulator private data */
        fe_modulation_t current_modulation;
+       u32 snr; /* Result of last SNR calculation */
 
        /* Tuner private data */
        u32 current_frequency;
@@ -465,124 +467,128 @@ static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
-     0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
-  1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
-  2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
-  2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
-  2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
-  2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
-  2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
-  3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
-  3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
-  3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
-  3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
-  3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
-  3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
-  3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
-  3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
-  3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
-  3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
-  3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
-  3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
-  3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
+/* Calculate SNR estimation (scaled by 2^24)
 
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+   8-VSB SNR and QAM equations from Oren datasheets
 
-static unsigned int i20Log10(unsigned short val)
-{
-       unsigned int rntval = 100;
-       unsigned int tmp = val;
-       unsigned int exp = 1;
+   For 8-VSB:
+     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K
+
+     Where K = 0 if NTSC rejection filter is OFF; and
+          K = 3 if NTSC rejection filter is ON
+
+   For QAM64:
+     SNR[dB] = 10 * log10(897152044.8282 / MSE^2 )
 
-       while(tmp > 100) {tmp /= 100; exp++;}
+   For QAM256:
+     SNR[dB] = 10 * log10(907832426.314266  / MSE^2 )
 
-       val = (2 * val)/denom[exp];
-       if (exp > 1) rntval = 2000*exp;
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for QAM256, c = log10(907832426.314266) * 2^24
+   and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */
 
-       rntval += i100x20log10[val];
-       return rntval;
+static u32 calculate_snr(u32 mse, u32 c)
+{
+       if (mse == 0) /* No signal */
+               return 0;
+
+       mse = 2*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 or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
 {
        struct or51132_state* state = fe->demodulator_priv;
-       unsigned char rec_buf[2];
-       unsigned char snd_buf[2];
-       u8 rcvr_stat;
-       u16 snr_equ;
-       u32 signal_strength;
-       int usK;
+       u8 rec_buf[2];
+       u8 snd_buf[2];
+       u32 noise;
+       u32 c;
+       u32 usK;
 
+       /* Register is same for VSB or QAM firmware */
        snd_buf[0]=0x04;
        snd_buf[1]=0x02; /* SNR after Equalizer */
        msleep(30); /* 30ms */
        if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-               printk(KERN_WARNING "or51132: read_status write error\n");
-               return -1;
+               printk(KERN_WARNING "or51132: snr write error\n");
+               return -EREMOTEIO;
        }
        msleep(30); /* 30ms */
        if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51132: read_status read error\n");
-               return -1;
+               printk(KERN_WARNING "or51132: snr read error\n");
+               return -EREMOTEIO;
        }
-       snr_equ = rec_buf[0] | (rec_buf[1] << 8);
-       dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+       noise = rec_buf[0] | (rec_buf[1] << 8);
+       dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise);
 
-       /* Receiver Status */
+       /* Read status, contains modulation type for QAM_AUTO and
+          NTSC filter for VSB */
        snd_buf[0]=0x04;
-       snd_buf[1]=0x00;
+       snd_buf[1]=0x00; /* Status register */
        msleep(30); /* 30ms */
        if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-               printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n");
-               return -1;
+               printk(KERN_WARNING "or51132: status write error\n");
+               return -EREMOTEIO;
        }
        msleep(30); /* 30ms */
        if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n");
-               return -1;
+               printk(KERN_WARNING "or51132: status read error\n");
+               return -EREMOTEIO;
        }
-       dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]);
-       rcvr_stat = rec_buf[1];
-       usK = (rcvr_stat & 0x10) ? 3 : 0;
 
-       /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-       signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
-       if (signal_strength > 0xffff)
-               *strength = 0xffff;
-       else
-               *strength = signal_strength;
-       dprintk("read_signal_strength %i\n",*strength);
+       usK = 0;
+       switch (rec_buf[0]) {
+       case 0x06:
+               usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0;
+               /* Fall through to QAM64 case */
+       case 0x43:
+               c = 150204167;
+               break;
+       case 0x45:
+               c = 150290396;
+               break;
+       default:
+               printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]);
+               return -EREMOTEIO;
+       }
+       dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__,
+               rec_buf[0], rec_buf[1]&0x10?"n":"ff");
+
+       /* Calculate SNR using noise, c, and NTSC rejection correction */
+       state->snr = calculate_snr(noise, c) - usK;
+       *snr = (state->snr) >> 16;
+
+       dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+               state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
        return 0;
 }
 
-static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
+static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-       struct or51132_state* state = fe->demodulator_priv;
-       unsigned char rec_buf[2];
-       unsigned char snd_buf[2];
-       u16 snr_equ;
-
-       snd_buf[0]=0x04;
-       snd_buf[1]=0x02; /* SNR after Equalizer */
-       msleep(30); /* 30ms */
-       if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-               printk(KERN_WARNING "or51132: read_snr write error\n");
-               return -1;
-       }
-       msleep(30); /* 30ms */
-       if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51132: read_snr dvr read error\n");
-               return -1;
-       }
-       snr_equ = rec_buf[0] | (rec_buf[1] << 8);
-       dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ);
+       /* 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 or51132_state* state = (struct or51132_state*) fe->demodulator_priv;
+       u16 snr;
+       int ret;
 
-       *snr = 0xFFFF - snr_equ;
-       dprintk("read_snr %i\n",*snr);
+       ret = fe->ops.read_snr(fe, &snr);
+       if (ret != 0)
+               return ret;
+       /* 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;
 
        return 0;
 }
index 2bf124b5368931da77a2320acd4c471e337a3087..048d7cfe12d30fa139d846aeb7200530379d477c 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
+#include "dvb_math.h"
 #include "dvb_frontend.h"
 #include "or51211.h"
 
@@ -63,6 +64,7 @@ struct or51211_state {
 
        /* Demodulator private data */
        u8 initialized:1;
+       u32 snr; /* Result of last SNR claculation */
 
        /* Tuner private data */
        u32 current_frequency;
@@ -292,107 +294,81 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
-               0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
-        1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
-        2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
-        2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
-        2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
-        2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
-        2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
-        3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
-        3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
-        3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
-        3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
-        3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
-        3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
-        3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
-        3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
-        3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
-        3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
-        3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
-        3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
-        3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
-
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+/* Calculate SNR estimation (scaled by 2^24)
 
-static unsigned int i20Log10(unsigned short val)
-{
-       unsigned int rntval = 100;
-       unsigned int tmp = val;
-       unsigned int exp = 1;
+   8-VSB SNR equation from Oren datasheets
 
-       while(tmp > 100) {tmp /= 100; exp++;}
+   For 8-VSB:
+     SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
 
-       val = (2 * val)/denom[exp];
-       if (exp > 1) rntval = 2000*exp;
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for 8-VSB, c = log10(219037.9454) * 2^24 */
 
-       rntval += i100x20log10[val];
-       return rntval;
+static u32 calculate_snr(u32 mse, u32 c)
+{
+       if (mse == 0) /* No signal */
+               return 0;
+
+       mse = 2*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 or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
 {
        struct or51211_state* state = fe->demodulator_priv;
        u8 rec_buf[2];
-       u8 snd_buf[4];
-       u8 snr_equ;
-       u32 signal_strength;
+       u8 snd_buf[3];
 
        /* SNR after Equalizer */
        snd_buf[0] = 0x04;
        snd_buf[1] = 0x00;
        snd_buf[2] = 0x04;
-       snd_buf[3] = 0x00;
 
        if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-               printk(KERN_WARNING "or51211: read_status write error\n");
+               printk(KERN_WARNING "%s: error writing snr reg\n",
+                      __FUNCTION__);
                return -1;
        }
-       msleep(3);
        if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51211: read_status read error\n");
+               printk(KERN_WARNING "%s: read_status read error\n",
+                      __FUNCTION__);
                return -1;
        }
-       snr_equ = rec_buf[0] & 0xff;
 
-       /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-       signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-       if (signal_strength > 0xffff)
-               *strength = 0xffff;
-       else
-               *strength = signal_strength;
-       dprintk("read_signal_strength %i\n",*strength);
+       state->snr = calculate_snr(rec_buf[0], 89599047);
+       *snr = (state->snr) >> 16;
+
+       dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __FUNCTION__, rec_buf[0],
+               state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
        return 0;
 }
 
-static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-       struct or51211_state* state = fe->demodulator_priv;
-       u8 rec_buf[2];
-       u8 snd_buf[4];
-
-       /* SNR after Equalizer */
-       snd_buf[0] = 0x04;
-       snd_buf[1] = 0x00;
-       snd_buf[2] = 0x04;
-       snd_buf[3] = 0x00;
-
-       if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-               printk(KERN_WARNING "or51211: read_status write error\n");
-               return -1;
-       }
-       msleep(3);
-       if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51211: read_status read error\n");
-               return -1;
-       }
-       *snr = rec_buf[0] & 0xff;
-
-       dprintk("read_snr %i\n",*snr);
+       /* 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 or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
+       u16 snr;
+       int ret;
+
+       ret = fe->ops.read_snr(fe, &snr);
+       if (ret != 0)
+               return ret;
+       /* 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;
 
        return 0;
 }
index 11e0dca9a2d7307de9e1a6648eedd4311844f9f1..00e4bcd9f1a4304e5ec99dbaeab0899af9b8de6e 100644 (file)
@@ -648,18 +648,24 @@ static int tda10046_init(struct dvb_frontend* fe)
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
                tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
                break;
-       case TDA10046_AGC_TDA827X:
+       case TDA10046_AGC_TDA827X_GP11:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
                tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
                tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
                tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
                break;
-       case TDA10046_AGC_TDA827X_GPL:
+       case TDA10046_AGC_TDA827X_GP00:
                tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
                tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
                tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
                tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
                break;
+       case TDA10046_AGC_TDA827X_GP01:
+               tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
+               tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
+               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities
+               break;
        }
        tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
        tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
index 605ad2dfc09db7454e81c45d5907f0c3e4284771..ec502d71b83c6c170a993d0604e705fd96a10338 100644 (file)
@@ -35,8 +35,9 @@ enum tda10046_agc {
        TDA10046_AGC_DEFAULT,           /* original configuration */
        TDA10046_AGC_IFO_AUTO_NEG,      /* IF AGC only, automatic, negtive */
        TDA10046_AGC_IFO_AUTO_POS,      /* IF AGC only, automatic, positive */
-       TDA10046_AGC_TDA827X,           /* IF AGC only, special setup for tda827x */
-       TDA10046_AGC_TDA827X_GPL,       /* same as above, but GPIOs 0 */
+       TDA10046_AGC_TDA827X_GP11,      /* IF AGC only, special setup for tda827x */
+       TDA10046_AGC_TDA827X_GP00,      /* same as above, but GPIOs 0 */
+       TDA10046_AGC_TDA827X_GP01,      /* same as above, but GPIO3=0 GPIO1=1*/
 };
 
 enum tda10046_if {
index 3aa45ebbac3da34252cb40d42f11c73f53abf7e6..67415c9db6f7ae180095355858b45045ad9829b7 100644 (file)
@@ -262,12 +262,29 @@ static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
        if (sync & 0x10)
                *status |= FE_HAS_SYNC;
 
+       if (sync & 0x20) /* frontend can not lock */
+               *status |= FE_TIMEDOUT;
+
        if ((sync & 0x1f) == 0x1f)
                *status |= FE_HAS_LOCK;
 
        return 0;
 }
 
+static int tda8083_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct tda8083_state* state = fe->demodulator_priv;
+       int ret;
+       u8 buf[3];
+
+       if ((ret = tda8083_readregs(state, 0x0b, buf, sizeof(buf))))
+               return ret;
+
+       *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
+
+       return 0;
+}
+
 static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
        struct tda8083_state* state = fe->demodulator_priv;
@@ -288,6 +305,17 @@ static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
        return 0;
 }
 
+static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct tda8083_state* state = fe->demodulator_priv;
+
+       *ucblocks = tda8083_readreg(state, 0x0f);
+       if (*ucblocks == 0xff)
+               *ucblocks = 0xffffffff;
+
+       return 0;
+}
+
 static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
        struct tda8083_state* state = fe->demodulator_priv;
@@ -440,6 +468,8 @@ static struct dvb_frontend_ops tda8083_ops = {
        .read_status = tda8083_read_status,
        .read_signal_strength = tda8083_read_signal_strength,
        .read_snr = tda8083_read_snr,
+       .read_ber = tda8083_read_ber,
+       .read_ucblocks = tda8083_read_ucblocks,
 
        .diseqc_send_master_cmd = tda8083_send_diseqc_msg,
        .diseqc_send_burst = tda8083_diseqc_send_burst,
index 34815b0b97e486964641d0337567bda932d691b8..79f971dc52b6d3bbe4a65b67df3f87744a975135 100644 (file)
@@ -42,8 +42,7 @@ struct tda826x_priv {
 
 static int tda826x_release(struct dvb_frontend *fe)
 {
-       if (fe->tuner_priv)
-               kfree(fe->tuner_priv);
+       kfree(fe->tuner_priv);
        fe->tuner_priv = NULL;
        return 0;
 }
@@ -133,18 +132,21 @@ struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2
 {
        struct tda826x_priv *priv = NULL;
        u8 b1 [] = { 0, 0 };
-       struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 };
+       struct i2c_msg msg[2] = {
+               { .addr = addr, .flags = 0,        .buf = NULL, .len = 0 },
+               { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 }
+       };
        int ret;
 
        dprintk("%s:\n", __FUNCTION__);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
-       ret = i2c_transfer (i2c, &msg, 1);
+       ret = i2c_transfer (i2c, msg, 2);
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
 
-       if (ret != 1)
+       if (ret != 2)
                return NULL;
        if (!(b1[1] & 0x80))
                return NULL;
index 88554393a9bf19627c427c159ed153ef30a4276e..6ba0029dcf2eee56e93315d10f089a47772f5a3d 100644 (file)
@@ -43,8 +43,7 @@ struct tua6100_priv {
 
 static int tua6100_release(struct dvb_frontend *fe)
 {
-       if (fe->tuner_priv)
-               kfree(fe->tuner_priv);
+       kfree(fe->tuner_priv);
        fe->tuner_priv = NULL;
        return 0;
 }
index 95531a624991644337b3f98dde9c98d8114e6f96..eec7ccf41f8bac51986f89926e9c023ca1743fb3 100644 (file)
@@ -92,6 +92,7 @@ config DVB_BUDGET_CI
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select VIDEO_IR
        help
          Support for simple SAA7146 based DVB cards
          (so called Budget- or Nova-PCI cards) without onboard
index bba23bcd1b11d813326464f80fe72cfd1ff16896..366c1371ee97dcf3e5eb41e8241fcc495a1aa5cc 100644 (file)
@@ -2828,7 +2828,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension av7110_extension = {
        .name           = "dvb",
-       .flags          = SAA7146_I2C_SHORT_DELAY,
+       .flags          = SAA7146_USE_I2C_IRQ,
 
        .module         = THIS_MODULE,
        .pci_tbl        = &pci_tbl[0],
index d54bbcdde2cce8c787587d3cb1dc8167fe45ba6d..e4544ea2b89b60e0a95b63160ce261a628bb40dc 100644 (file)
@@ -48,7 +48,8 @@ static void av7110_emit_keyup(unsigned long data)
        if (!data || !test_bit(data, input_dev->key))
                return;
 
-       input_event(input_dev, EV_KEY, data, !!0);
+       input_report_key(input_dev, data, 0);
+       input_sync(input_dev);
 }
 
 
@@ -115,14 +116,17 @@ static void av7110_emit_key(unsigned long parm)
                del_timer(&keyup_timer);
                if (keyup_timer.data != keycode || new_toggle != old_toggle) {
                        delay_timer_finished = 0;
-                       input_event(input_dev, EV_KEY, keyup_timer.data, !!0);
-                       input_event(input_dev, EV_KEY, keycode, !0);
-               } else
-                       if (delay_timer_finished)
-                               input_event(input_dev, EV_KEY, keycode, 2);
+                       input_event(input_dev, EV_KEY, keyup_timer.data, 0);
+                       input_event(input_dev, EV_KEY, keycode, 1);
+                       input_sync(input_dev);
+               } else if (delay_timer_finished) {
+                       input_event(input_dev, EV_KEY, keycode, 2);
+                       input_sync(input_dev);
+               }
        } else {
                delay_timer_finished = 0;
-               input_event(input_dev, EV_KEY, keycode, !0);
+               input_event(input_dev, EV_KEY, keycode, 1);
+               input_sync(input_dev);
        }
 
        keyup_timer.expires = jiffies + UP_TIMEOUT;
@@ -211,6 +215,7 @@ static void ir_handler(struct av7110 *av7110, u32 ircom)
 int __devinit av7110_ir_init(struct av7110 *av7110)
 {
        static struct proc_dir_entry *e;
+       int err;
 
        if (av_cnt >= sizeof av_list/sizeof av_list[0])
                return -ENOSPC;
@@ -231,7 +236,11 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
                set_bit(EV_KEY, input_dev->evbit);
                set_bit(EV_REP, input_dev->evbit);
                input_register_keys();
-               input_register_device(input_dev);
+               err = input_register_device(input_dev);
+               if (err) {
+                       input_free_device(input_dev);
+                       return err;
+               }
                input_dev->timer.function = input_repeat_key;
 
                e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
index 2235ff8b8a1d06b35f9273fe7dd832d8591c6b3a..89ab4b59155cde27035bcb4ce4d8f3a887c8eac7 100644 (file)
@@ -360,7 +360,7 @@ static int ciintf_init(struct budget_av *budget_av)
        saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
 
        /* Enable DEBI pins */
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+       saa7146_write(saa, MC1, MASK_27 | MASK_11);
 
        /* register CI interface */
        budget_av->ca.owner = THIS_MODULE;
@@ -386,7 +386,7 @@ static int ciintf_init(struct budget_av *budget_av)
        return 0;
 
 error:
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+       saa7146_write(saa, MC1, MASK_27);
        return result;
 }
 
@@ -403,7 +403,7 @@ static void ciintf_deinit(struct budget_av *budget_av)
        dvb_ca_en50221_release(&budget_av->ca);
 
        /* disable DEBI pins */
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+       saa7146_write(saa, MC1, MASK_27);
 }
 
 
@@ -655,6 +655,10 @@ static struct tda10021_config philips_cu1216_config = {
        .demod_address = 0x0c,
 };
 
+static struct tda10021_config philips_cu1216_config_altaddress = {
+       .demod_address = 0x0d,
+};
+
 
 
 
@@ -831,7 +835,7 @@ static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
                return -EINVAL;
 
        rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
-                       params->frequency, 0);
+                            params->frequency, 0);
        if(rc < 0) return rc;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -914,6 +918,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBS_TV_STAR_CI  0x0016
 #define SUBID_DVBS_EASYWATCH_1  0x001a
 #define SUBID_DVBS_EASYWATCH   0x001e
+#define SUBID_DVBC_EASYWATCH   0x002a
 #define SUBID_DVBC_KNC1                0x0020
 #define SUBID_DVBC_KNC1_PLUS   0x0021
 #define SUBID_DVBC_CINERGY1200 0x1156
@@ -947,11 +952,15 @@ static void frontend_init(struct budget_av *budget_av)
        /* Enable / PowerON Frontend */
        saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
 
+       /* Wait for PowerON */
+       msleep(100);
+
        /* additional setup necessary for the PLUS cards */
        switch (saa->pci->subsystem_device) {
                case SUBID_DVBS_KNC1_PLUS:
                case SUBID_DVBC_KNC1_PLUS:
                case SUBID_DVBT_KNC1_PLUS:
+               case SUBID_DVBC_EASYWATCH:
                        saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
                        break;
        }
@@ -1006,10 +1015,15 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBC_KNC1:
        case SUBID_DVBC_KNC1_PLUS:
        case SUBID_DVBC_CINERGY1200:
+       case SUBID_DVBC_EASYWATCH:
                budget_av->reinitialise_demod = 1;
                fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
                                     &budget_av->budget.i2c_adap,
                                     read_pwm(budget_av));
+               if (fe == NULL)
+                       fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress,
+                                            &budget_av->budget.i2c_adap,
+                                            read_pwm(budget_av));
                if (fe) {
                        budget_av->tda10021_poclkp = 1;
                        budget_av->tda10021_set_frontend = fe->ops.set_frontend;
@@ -1242,6 +1256,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1260,6 +1275,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
        MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
        MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+       MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
        MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
        MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
@@ -1277,7 +1293,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
        .name = "budget_av",
-       .flags = SAA7146_I2C_SHORT_DELAY,
+       .flags = SAA7146_USE_I2C_IRQ,
 
        .pci_tbl = pci_tbl,
 
index cd5ec489af1cdd9a0bc097242d9e307fb3cd6ef5..f2066b47baee6ce9d61358b7aea5e35a6f4891c9 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/spinlock.h>
+#include <media/ir-common.h>
 
 #include "dvb_ca_en50221.h"
 #include "stv0299.h"
 #define SLOTSTATUS_READY       8
 #define SLOTSTATUS_OCCUPIED    (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
 
+/* Milliseconds during which key presses are regarded as key repeat and during
+ * which the debounce logic is active
+ */
+#define IR_REPEAT_TIMEOUT      350
+
+/* RC5 device wildcard */
+#define IR_DEVICE_ANY          255
+
+/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
+ * this setting allows the superflous sequences to be ignored
+ */
+static int debounce = 0;
+module_param(debounce, int, 0644);
+MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
+
+static int rc5_device = -1;
+module_param(rc5_device, int, 0644);
+MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
+
+static int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
+
+struct budget_ci_ir {
+       struct input_dev *dev;
+       struct tasklet_struct msp430_irq_tasklet;
+       char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
+       char phys[32];
+       struct ir_input_state state;
+       int rc5_device;
+};
+
 struct budget_ci {
        struct budget budget;
-       struct input_dev *input_dev;
-       struct tasklet_struct msp430_irq_tasklet;
        struct tasklet_struct ciintf_irq_tasklet;
        int slot_status;
        int ci_irq;
        struct dvb_ca_en50221 ca;
-       char ir_dev_name[50];
+       struct budget_ci_ir ir;
        u8 tuner_pll_address; /* used for philips_tdm1316l configs */
 };
 
-/* from reading the following remotes:
-   Zenith Universal 7 / TV Mode 807 / VCR Mode 837
-   Hauppauge (from NOVA-CI-s box product)
-   i've taken a "middle of the road" approach and note the differences
-*/
-static u16 key_map[64] = {
-       /* 0x0X */
-       KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
-       KEY_9,
-       KEY_ENTER,
-       KEY_RED,
-       KEY_POWER,              /* RADIO on Hauppauge */
-       KEY_MUTE,
-       0,
-       KEY_A,                  /* TV on Hauppauge */
-       /* 0x1X */
-       KEY_VOLUMEUP, KEY_VOLUMEDOWN,
-       0, 0,
-       KEY_B,
-       0, 0, 0, 0, 0, 0, 0,
-       KEY_UP, KEY_DOWN,
-       KEY_OPTION,             /* RESERVED on Hauppauge */
-       KEY_BREAK,
-       /* 0x2X */
-       KEY_CHANNELUP, KEY_CHANNELDOWN,
-       KEY_PREVIOUS,           /* Prev. Ch on Zenith, SOURCE on Hauppauge */
-       0, KEY_RESTART, KEY_OK,
-       KEY_CYCLEWINDOWS,       /* MINIMIZE on Hauppauge */
-       0,
-       KEY_ENTER,              /* VCR mode on Zenith */
-       KEY_PAUSE,
-       0,
-       KEY_RIGHT, KEY_LEFT,
-       0,
-       KEY_MENU,               /* FULL SCREEN on Hauppauge */
-       0,
-       /* 0x3X */
-       KEY_SLOW,
-       KEY_PREVIOUS,           /* VCR mode on Zenith */
-       KEY_REWIND,
-       0,
-       KEY_FASTFORWARD,
-       KEY_PLAY, KEY_STOP,
-       KEY_RECORD,
-       KEY_TUNER,              /* TV/VCR on Zenith */
-       0,
-       KEY_C,
-       0,
-       KEY_EXIT,
-       KEY_POWER2,
-       KEY_TUNER,              /* VCR mode on Zenith */
-       0,
-};
-
-static void msp430_ir_debounce(unsigned long data)
+static void msp430_ir_keyup(unsigned long data)
 {
-       struct input_dev *dev = (struct input_dev *) data;
-
-       if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
-               input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
-               return;
-       }
-
-       dev->rep[0] = 0;
-       dev->timer.expires = jiffies + HZ * 350 / 1000;
-       add_timer(&dev->timer);
-       input_event(dev, EV_KEY, key_map[dev->repeat_key], 2);  /* REPEAT */
+       struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
+       ir_input_nokey(ir->dev, &ir->state);
 }
 
 static void msp430_ir_interrupt(unsigned long data)
 {
        struct budget_ci *budget_ci = (struct budget_ci *) data;
-       struct input_dev *dev = budget_ci->input_dev;
-       unsigned int code =
-               ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+       struct input_dev *dev = budget_ci->ir.dev;
+       static int bounces = 0;
+       int device;
+       int toggle;
+       static int prev_toggle = -1;
+       static u32 ir_key;
+       u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+
+       /*
+        * The msp430 chip can generate two different bytes, command and device
+        *
+        * type1: X1CCCCCC, C = command bits (0 - 63)
+        * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
+        *
+        * More than one command byte may be generated before the device byte
+        * Only when we have both, a correct keypress is generated
+        */
+
+       /* Is this a RC5 command byte? */
+       if (command & 0x40) {
+               if (ir_debug)
+                       printk("budget_ci: received command byte 0x%02x\n", command);
+               ir_key = command & 0x3f;
+               return;
+       }
 
-       if (code & 0x40) {
-               code &= 0x3f;
+       /* It's a RC5 device byte */
+       if (ir_debug)
+               printk("budget_ci: received device byte 0x%02x\n", command);
+       device = command & 0x1f;
+       toggle = command & 0x20;
 
-               if (timer_pending(&dev->timer)) {
-                       if (code == dev->repeat_key) {
-                               ++dev->rep[0];
-                               return;
-                       }
-                       del_timer(&dev->timer);
-                       input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
-               }
+       if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
+               return;
 
-               if (!key_map[code]) {
-                       printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
-                       return;
-               }
+       /* Ignore repeated key sequences if requested */
+       if (toggle == prev_toggle && ir_key == dev->repeat_key &&
+           bounces > 0 && timer_pending(&dev->timer)) {
+               if (ir_debug)
+                       printk("budget_ci: debounce logic ignored IR command\n");
+               bounces--;
+               return;
+       }
+       prev_toggle = toggle;
 
-               /* initialize debounce and repeat */
-               dev->repeat_key = code;
-               /* Zenith remote _always_ sends 2 sequences */
-               dev->rep[0] = ~0;
-               /* 350 milliseconds */
-               dev->timer.expires = jiffies + HZ * 350 / 1000;
-               /* MAKE */
-               input_event(dev, EV_KEY, key_map[code], !0);
-               add_timer(&dev->timer);
+       /* Are we still waiting for a keyup event? */
+       if (del_timer(&dev->timer))
+               ir_input_nokey(dev, &budget_ci->ir.state);
+
+       /* Generate keypress */
+       if (ir_debug)
+               printk("budget_ci: generating keypress 0x%02x\n", ir_key);
+       ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
+
+       /* Do we want to delay the keyup event? */
+       if (debounce) {
+               bounces = debounce;
+               mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
+       } else {
+               ir_input_nokey(dev, &budget_ci->ir.state);
        }
 }
 
 static int msp430_ir_init(struct budget_ci *budget_ci)
 {
        struct saa7146_dev *saa = budget_ci->budget.dev;
-       struct input_dev *input_dev;
-       int i;
+       struct input_dev *input_dev = budget_ci->ir.dev;
+       int error;
+
+       budget_ci->ir.dev = input_dev = input_allocate_device();
+       if (!input_dev) {
+               printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
+               error = -ENOMEM;
+               goto out1;
+       }
+
+       snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
+                "Budget-CI dvb ir receiver %s", saa->name);
+       snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
+                "pci-%s/ir0", pci_name(saa->pci));
 
-       budget_ci->input_dev = input_dev = input_allocate_device();
-       if (!input_dev)
-               return -ENOMEM;
+       input_dev->name = budget_ci->ir.name;
 
-       sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
+       input_dev->phys = budget_ci->ir.phys;
+       input_dev->id.bustype = BUS_PCI;
+       input_dev->id.version = 1;
+       if (saa->pci->subsystem_vendor) {
+               input_dev->id.vendor = saa->pci->subsystem_vendor;
+               input_dev->id.product = saa->pci->subsystem_device;
+       } else {
+               input_dev->id.vendor = saa->pci->vendor;
+               input_dev->id.product = saa->pci->device;
+       }
+       input_dev->cdev.dev = &saa->pci->dev;
 
-       input_dev->name = budget_ci->ir_dev_name;
+       /* Select keymap and address */
+       switch (budget_ci->budget.dev->pci->subsystem_device) {
+       case 0x100c:
+       case 0x100f:
+       case 0x1010:
+       case 0x1011:
+       case 0x1012:
+       case 0x1017:
+               /* The hauppauge keymap is a superset of these remotes */
+               ir_input_init(input_dev, &budget_ci->ir.state,
+                             IR_TYPE_RC5, ir_codes_hauppauge_new);
+
+               if (rc5_device < 0)
+                       budget_ci->ir.rc5_device = 0x1f;
+               else
+                       budget_ci->ir.rc5_device = rc5_device;
+               break;
+       default:
+               /* unknown remote */
+               ir_input_init(input_dev, &budget_ci->ir.state,
+                             IR_TYPE_RC5, ir_codes_budget_ci_old);
+
+               if (rc5_device < 0)
+                       budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+               else
+                       budget_ci->ir.rc5_device = rc5_device;
+               break;
+       }
 
-       set_bit(EV_KEY, input_dev->evbit);
-       for (i = 0; i < ARRAY_SIZE(key_map); i++)
-               if (key_map[i])
-                       set_bit(key_map[i], input_dev->keybit);
+       /* initialise the key-up debounce timeout handler */
+       input_dev->timer.function = msp430_ir_keyup;
+       input_dev->timer.data = (unsigned long) &budget_ci->ir;
 
-       input_register_device(budget_ci->input_dev);
+       error = input_register_device(input_dev);
+       if (error) {
+               printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
+               goto out2;
+       }
 
-       input_dev->timer.function = msp430_ir_debounce;
+       tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
+                    (unsigned long) budget_ci);
 
-       saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
+       SAA7146_IER_ENABLE(saa, MASK_06);
        saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
 
        return 0;
+
+out2:
+       input_free_device(input_dev);
+out1:
+       return error;
 }
 
 static void msp430_ir_deinit(struct budget_ci *budget_ci)
 {
        struct saa7146_dev *saa = budget_ci->budget.dev;
-       struct input_dev *dev = budget_ci->input_dev;
+       struct input_dev *dev = budget_ci->ir.dev;
 
-       saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
+       SAA7146_IER_DISABLE(saa, MASK_06);
        saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+       tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
 
-       if (del_timer(&dev->timer))
-               input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
+       if (del_timer(&dev->timer)) {
+               ir_input_nokey(dev, &budget_ci->ir.state);
+               input_sync(dev);
+       }
 
        input_unregister_device(dev);
 }
@@ -428,7 +485,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
        memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
 
        // enable DEBI pins
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+       saa7146_write(saa, MC1, MASK_27 | MASK_11);
 
        // test if it is there
        ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
@@ -480,7 +537,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
                } else {
                        saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
                }
-               saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
+               SAA7146_IER_ENABLE(saa, MASK_03);
        }
 
        // enable interface
@@ -502,7 +559,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
        return 0;
 
 error:
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+       saa7146_write(saa, MC1, MASK_27);
        return result;
 }
 
@@ -512,7 +569,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
 
        // disable CI interrupts
        if (budget_ci->ci_irq) {
-               saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
+               SAA7146_IER_DISABLE(saa, MASK_03);
                saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
                tasklet_kill(&budget_ci->ciintf_irq_tasklet);
        }
@@ -530,7 +587,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
        dvb_ca_en50221_release(&budget_ci->ca);
 
        // disable DEBI pins
-       saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+       saa7146_write(saa, MC1, MASK_27);
 }
 
 static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
@@ -540,7 +597,7 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
        dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
 
        if (*isr & MASK_06)
-               tasklet_schedule(&budget_ci->msp430_irq_tasklet);
+               tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
 
        if (*isr & MASK_10)
                ttpci_budget_irq10_handler(dev, isr);
@@ -835,7 +892,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
                band = 1;
        } else if (tuner_frequency < 200000000) {
                cp = 6;
-               band = 1;
+               band = 2;
        } else if (tuner_frequency < 290000000) {
                cp = 3;
                band = 2;
@@ -1083,24 +1140,23 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
        struct budget_ci *budget_ci;
        int err;
 
-       if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
-               return -ENOMEM;
+       budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
+       if (!budget_ci) {
+               err = -ENOMEM;
+               goto out1;
+       }
 
        dprintk(2, "budget_ci: %p\n", budget_ci);
 
-       budget_ci->budget.ci_present = 0;
-
        dev->ext_priv = budget_ci;
 
-       if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
-               kfree(budget_ci);
-               return err;
-       }
-
-       tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
-                    (unsigned long) budget_ci);
+       err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
+       if (err)
+               goto out2;
 
-       msp430_ir_init(budget_ci);
+       err = msp430_ir_init(budget_ci);
+       if (err)
+               goto out3;
 
        ciintf_init(budget_ci);
 
@@ -1110,6 +1166,13 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
        ttpci_budget_init_hooks(&budget_ci->budget);
 
        return 0;
+
+out3:
+       ttpci_budget_deinit(&budget_ci->budget);
+out2:
+       kfree(budget_ci);
+out1:
+       return err;
 }
 
 static int budget_ci_detach(struct saa7146_dev *dev)
@@ -1120,16 +1183,13 @@ static int budget_ci_detach(struct saa7146_dev *dev)
 
        if (budget_ci->budget.ci_present)
                ciintf_deinit(budget_ci);
+       msp430_ir_deinit(budget_ci);
        if (budget_ci->budget.dvb_frontend) {
                dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
                dvb_frontend_detach(budget_ci->budget.dvb_frontend);
        }
        err = ttpci_budget_deinit(&budget_ci->budget);
 
-       tasklet_kill(&budget_ci->msp430_irq_tasklet);
-
-       msp430_ir_deinit(budget_ci);
-
        // disable frontend and CI interface
        saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
 
@@ -1162,7 +1222,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
        .name = "budget_ci dvb",
-       .flags = SAA7146_I2C_SHORT_DELAY,
+       .flags = SAA7146_USE_I2C_IRQ,
 
        .module = THIS_MODULE,
        .pci_tbl = &pci_tbl[0],
index 56f1c80defc63deead3ec65349f727408ace2e7f..9268a82bada6c65f42f3b2af9935275965d2d3bd 100644 (file)
@@ -555,7 +555,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct saa7146_extension budget_extension = {
        .name           = "budget dvb",
-       .flags          = SAA7146_I2C_SHORT_DELAY,
+       .flags          = SAA7146_USE_I2C_IRQ,
 
        .module         = THIS_MODULE,
        .pci_tbl        = pci_tbl,
index 10b121ada833b403b0ff4ef5140f5698f729532a..bd6e7baae2ec9d6bd5d53f0b5b04d414b51a432a 100644 (file)
@@ -238,6 +238,7 @@ static void ttusb_dec_handle_irq( struct urb *urb)
                 * for now lets report each signal as a key down and up*/
                dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
                input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
+               input_sync(dec->rc_input_dev);
                input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
                input_sync(dec->rc_input_dev);
        }
@@ -1187,11 +1188,12 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
        struct input_dev *input_dev;
        u8 b[] = { 0x00, 0x01 };
        int i;
+       int err;
 
        usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
        strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
 
-       dec->rc_input_dev = input_dev = input_allocate_device();
+       input_dev = input_allocate_device();
        if (!input_dev)
                return -ENOMEM;
 
@@ -1205,8 +1207,13 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
        for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
                  set_bit(rc_keys[i], input_dev->keybit);
 
-       input_register_device(input_dev);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
 
+       dec->rc_input_dev = input_dev;
        if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
                printk("%s: usb_submit_urb failed\n",__FUNCTION__);
        /* enable irq pipe */
index b8fde5cf4735567919c3dfa19e79ca99940018d2..29a11c1db1b7e3c040f591a640efd427fe634c03 100644 (file)
@@ -184,6 +184,14 @@ config VIDEO_KS0127
          To compile this driver as a module, choose M here: the
          module will be called ks0127.
 
+config VIDEO_OV7670
+       tristate "OmniVision OV7670 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the OmniVision
+         OV7670 VGA camera.  It currently only works with the M88ALP01
+         controller.
+
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
        depends on VIDEO_V4L1 && I2C
@@ -567,18 +575,6 @@ config VIDEO_ZORAN_AVS6EYES
        help
          Support for the AverMedia 6 Eyes video surveillance card.
 
-config VIDEO_ZR36120
-       tristate "Zoran ZR36120/36125 Video For Linux"
-       depends on PCI && I2C && VIDEO_V4L1 && BROKEN
-       help
-         Support for ZR36120/ZR36125 based frame grabber/overlay boards.
-         This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV,
-         and Buster boards. Please read the material in
-         <file:Documentation/video4linux/zr36120.txt> for more information.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zr36120.
-
 config VIDEO_MEYE
        tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
        depends on PCI && SONYPI && VIDEO_V4L1
@@ -670,6 +666,15 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
+config VIDEO_CAFE_CCIC
+       tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
+       depends on I2C && VIDEO_V4L2
+       select VIDEO_OV7670
+       ---help---
+         This is a video4linux2 driver for the Marvell 88ALP01 integrated
+         CMOS camera controller.  This is the controller found on first-
+         generation OLPC systems.
+
 #
 # USB Multimedia device configuration
 #
@@ -681,6 +686,8 @@ source "drivers/media/video/pvrusb2/Kconfig"
 
 source "drivers/media/video/em28xx/Kconfig"
 
+source "drivers/media/video/usbvision/Kconfig"
+
 source "drivers/media/video/usbvideo/Kconfig"
 
 source "drivers/media/video/et61x251/Kconfig"
index af57abce8a6ecc9ccdcefd0e9724775704581d1f..9b1f3f06bb7ce267d5dc868be48b4e2dd6965cc4 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for the video capture/playback device drivers.
 #
 
-zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
 tuner-objs     :=      tuner-core.o tuner-types.o tuner-simple.o \
@@ -23,7 +22,6 @@ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
-obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
@@ -64,6 +62,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
@@ -92,6 +91,9 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
 obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
index 6e1ddad9f0c1135d492f9c788496ebc4ebfbb578..3c8e4742dccc9fec77d25368cd6e4e989258d651 100644 (file)
@@ -1793,7 +1793,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                memset(i,0,sizeof(*i));
                i->index    = n;
                i->type     = V4L2_INPUT_TYPE_CAMERA;
-               i->audioset = 0;
+               i->audioset = 1;
                if (i->index == bttv_tvcards[btv->c.type].tuner) {
                        sprintf(i->name, "Television");
                        i->type  = V4L2_INPUT_TYPE_TUNER;
index 933d6db09acb377025c8e23c8a67d8ac51dd39d2..cbc012f71f5269e7b570195139ca88f426710286 100644 (file)
@@ -259,24 +259,59 @@ static void bttv_rc5_timer_keyup(unsigned long data)
 
 /* ---------------------------------------------------------------------- */
 
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+{
+       if (ir->polling) {
+               init_timer(&ir->timer);
+               ir->timer.function = bttv_input_timer;
+               ir->timer.data     = (unsigned long)btv;
+               ir->timer.expires  = jiffies + HZ;
+               add_timer(&ir->timer);
+       } else if (ir->rc5_gpio) {
+               /* set timer_end for code completion */
+               init_timer(&ir->timer_end);
+               ir->timer_end.function = bttv_rc5_timer_end;
+               ir->timer_end.data = (unsigned long)ir;
+
+               init_timer(&ir->timer_keyup);
+               ir->timer_keyup.function = bttv_rc5_timer_keyup;
+               ir->timer_keyup.data = (unsigned long)ir;
+       }
+}
+
+static void bttv_ir_stop(struct bttv *btv)
+{
+       if (btv->remote->polling) {
+               del_timer_sync(&btv->remote->timer);
+               flush_scheduled_work();
+       }
+
+       if (btv->remote->rc5_gpio) {
+               u32 gpio;
+
+               del_timer_sync(&btv->remote->timer_end);
+               flush_scheduled_work();
+
+               gpio = bttv_gpio_read(&btv->c);
+               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+       }
+}
+
 int bttv_input_init(struct bttv *btv)
 {
        struct bttv_ir *ir;
        IR_KEYTAB_TYPE *ir_codes = NULL;
        struct input_dev *input_dev;
        int ir_type = IR_TYPE_OTHER;
+       int err = -ENOMEM;
 
        if (!btv->has_remote)
                return -ENODEV;
 
        ir = kzalloc(sizeof(*ir),GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!ir || !input_dev) {
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENOMEM;
-       }
-       memset(ir,0,sizeof(*ir));
+       if (!ir || !input_dev)
+               goto err_out_free;
 
        /* detect & configure */
        switch (btv->c.type) {
@@ -348,10 +383,9 @@ int bttv_input_init(struct bttv *btv)
                break;
        }
        if (NULL == ir_codes) {
-               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENODEV;
+               dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
+               err = -ENODEV;
+               goto err_out_free;
        }
 
        if (ir->rc5_gpio) {
@@ -389,32 +423,26 @@ int bttv_input_init(struct bttv *btv)
        input_dev->cdev.dev = &btv->c.pci->dev;
 
        btv->remote = ir;
-       if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = bttv_input_timer;
-               ir->timer.data     = (unsigned long)btv;
-               ir->timer.expires  = jiffies + HZ;
-               add_timer(&ir->timer);
-       } else if (ir->rc5_gpio) {
-               /* set timer_end for code completion */
-               init_timer(&ir->timer_end);
-               ir->timer_end.function = bttv_rc5_timer_end;
-               ir->timer_end.data = (unsigned long)ir;
-
-               init_timer(&ir->timer_keyup);
-               ir->timer_keyup.function = bttv_rc5_timer_keyup;
-               ir->timer_keyup.data = (unsigned long)ir;
-       }
+       bttv_ir_start(btv, ir);
 
        /* all done */
-       input_register_device(btv->remote->dev);
-       printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+       err = input_register_device(btv->remote->dev);
+       if (err)
+               goto err_out_stop;
 
        /* the remote isn't as bouncy as a keyboard */
        ir->dev->rep[REP_DELAY] = repeat_delay;
        ir->dev->rep[REP_PERIOD] = repeat_period;
 
        return 0;
+
+ err_out_stop:
+       bttv_ir_stop(btv);
+       btv->remote = NULL;
+ err_out_free:
+       input_free_device(input_dev);
+       kfree(ir);
+       return err;
 }
 
 void bttv_input_fini(struct bttv *btv)
@@ -422,22 +450,7 @@ void bttv_input_fini(struct bttv *btv)
        if (btv->remote == NULL)
                return;
 
-       if (btv->remote->polling) {
-               del_timer_sync(&btv->remote->timer);
-               flush_scheduled_work();
-       }
-
-
-       if (btv->remote->rc5_gpio) {
-               u32 gpio;
-
-               del_timer_sync(&btv->remote->timer_end);
-               flush_scheduled_work();
-
-               gpio = bttv_gpio_read(&btv->c);
-               bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
-       }
-
+       bttv_ir_stop(btv);
        input_unregister_device(btv->remote->dev);
        kfree(btv->remote);
        btv->remote = NULL;
diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h
new file mode 100644 (file)
index 0000000..b2c22a0
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Register definitions for the m88alp01 camera interface.  Offsets in bytes
+ * as given in the spec.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#define REG_Y0BAR      0x00
+#define REG_Y1BAR      0x04
+#define REG_Y2BAR      0x08
+/* ... */
+
+#define REG_IMGPITCH   0x24    /* Image pitch register */
+#define   IMGP_YP_SHFT   2             /* Y pitch params */
+#define   IMGP_YP_MASK   0x00003ffc    /* Y pitch field */
+#define          IMGP_UVP_SHFT   18            /* UV pitch (planar) */
+#define   IMGP_UVP_MASK   0x3ffc0000
+#define REG_IRQSTATRAW 0x28    /* RAW IRQ Status */
+#define   IRQ_EOF0       0x00000001    /* End of frame 0 */
+#define   IRQ_EOF1       0x00000002    /* End of frame 1 */
+#define   IRQ_EOF2       0x00000004    /* End of frame 2 */
+#define   IRQ_SOF0       0x00000008    /* Start of frame 0 */
+#define   IRQ_SOF1       0x00000010    /* Start of frame 1 */
+#define   IRQ_SOF2       0x00000020    /* Start of frame 2 */
+#define   IRQ_OVERFLOW   0x00000040    /* FIFO overflow */
+#define   IRQ_TWSIW      0x00010000    /* TWSI (smbus) write */
+#define   IRQ_TWSIR      0x00020000    /* TWSI read */
+#define   IRQ_TWSIE      0x00040000    /* TWSI error */
+#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
+#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
+#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
+#define REG_IRQMASK    0x2c    /* IRQ mask - same bits as IRQSTAT */
+#define REG_IRQSTAT    0x30    /* IRQ status / clear */
+
+#define REG_IMGSIZE    0x34    /* Image size */
+#define  IMGSZ_V_MASK    0x1fff0000
+#define  IMGSZ_V_SHIFT   16
+#define         IMGSZ_H_MASK     0x00003fff
+#define REG_IMGOFFSET  0x38    /* IMage offset */
+
+#define REG_CTRL0      0x3c    /* Control 0 */
+#define   C0_ENABLE      0x00000001    /* Makes the whole thing go */
+
+/* Mask for all the format bits */
+#define   C0_DF_MASK     0x00fffffc    /* Bits 2-23 */
+
+/* RGB ordering */
+#define   C0_RGB4_RGBX   0x00000000
+#define          C0_RGB4_XRGB    0x00000004
+#define          C0_RGB4_BGRX    0x00000008
+#define   C0_RGB4_XBGR   0x0000000c
+#define   C0_RGB5_RGGB   0x00000000
+#define          C0_RGB5_GRBG    0x00000004
+#define          C0_RGB5_GBRG    0x00000008
+#define   C0_RGB5_BGGR   0x0000000c
+
+/* Spec has two fields for DIN and DOUT, but they must match, so
+   combine them here. */
+#define   C0_DF_YUV      0x00000000    /* Data is YUV      */
+#define   C0_DF_RGB      0x000000a0    /* ... RGB                  */
+#define   C0_DF_BAYER     0x00000140   /* ... Bayer                */
+/* 8-8-8 must be missing from the below - ask */
+#define   C0_RGBF_565    0x00000000
+#define   C0_RGBF_444    0x00000800
+#define   C0_RGB_BGR     0x00001000    /* Blue comes first */
+#define   C0_YUV_PLANAR          0x00000000    /* YUV 422 planar format */
+#define   C0_YUV_PACKED          0x00008000    /* YUV 422 packed       */
+#define   C0_YUV_420PL   0x0000a000    /* YUV 420 planar       */
+/* Think that 420 packed must be 111 - ask */
+#define          C0_YUVE_YUYV    0x00000000    /* Y1CbY0Cr             */
+#define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
+#define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
+#define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
+#define   C0_YUVE_XYUV   0x00000000    /* 420: .YUV            */
+#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
+#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
+#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
+/* Bayer bits 18,19 if needed */
+#define   C0_HPOL_LOW    0x01000000    /* HSYNC polarity active low */
+#define   C0_VPOL_LOW    0x02000000    /* VSYNC polarity active low */
+#define   C0_VCLK_LOW    0x04000000    /* VCLK on falling edge */
+#define   C0_DOWNSCALE   0x08000000    /* Enable downscaler */
+#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
+#define   C0_SIF_HVSYNC          0x00000000    /* Use H/VSYNC */
+#define   CO_SOF_NOSYNC          0x40000000    /* Use inband active signaling */
+
+
+#define REG_CTRL1      0x40    /* Control 1 */
+#define   C1_444ALPHA    0x00f00000    /* Alpha field in RGB444 */
+#define   C1_ALPHA_SHFT          20
+#define   C1_DMAB32      0x00000000    /* 32-byte DMA burst */
+#define   C1_DMAB16      0x02000000    /* 16-byte DMA burst */
+#define          C1_DMAB64       0x04000000    /* 64-byte DMA burst */
+#define          C1_DMAB_MASK    0x06000000
+#define   C1_TWOBUFS     0x08000000    /* Use only two DMA buffers */
+#define   C1_PWRDWN      0x10000000    /* Power down */
+
+#define REG_CLKCTRL    0x88    /* Clock control */
+#define   CLK_DIV_MASK   0x0000ffff    /* Upper bits RW "reserved" */
+
+#define REG_GPR                0xb4    /* General purpose register.  This
+                                  controls inputs to the power and reset
+                                  pins on the OV7670 used with OLPC;
+                                  other deployments could differ.  */
+#define   GPR_C1EN       0x00000020    /* Pad 1 (power down) enable */
+#define   GPR_C0EN       0x00000010    /* Pad 0 (reset) enable */
+#define          GPR_C1          0x00000002    /* Control 1 value */
+/*
+ * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
+ * it is active low, for 0v6x, instead, it's active high.  What
+ * fun.
+ */
+#define   GPR_C0         0x00000001    /* Control 0 value */
+
+#define REG_TWSIC0     0xb8    /* TWSI (smbus) control 0 */
+#define   TWSIC0_EN       0x00000001   /* TWSI enable */
+#define   TWSIC0_MODE    0x00000002    /* 1 = 16-bit, 0 = 8-bit */
+#define   TWSIC0_SID     0x000003fc    /* Slave ID */
+#define   TWSIC0_SID_SHIFT 2
+#define   TWSIC0_CLKDIV   0x0007fc00   /* Clock divider */
+#define   TWSIC0_MASKACK  0x00400000   /* Mask ack from sensor */
+#define   TWSIC0_OVMAGIC  0x00800000   /* Make it work on OV sensors */
+
+#define REG_TWSIC1     0xbc    /* TWSI control 1 */
+#define   TWSIC1_DATA    0x0000ffff    /* Data to/from camchip */
+#define   TWSIC1_ADDR    0x00ff0000    /* Address (register) */
+#define   TWSIC1_ADDR_SHIFT 16
+#define   TWSIC1_READ    0x01000000    /* Set for read op */
+#define   TWSIC1_WSTAT   0x02000000    /* Write status */
+#define   TWSIC1_RVALID          0x04000000    /* Read data valid */
+#define   TWSIC1_ERROR   0x08000000    /* Something screwed up */
+
+
+#define REG_UBAR       0xc4    /* Upper base address register */
+
+/*
+ * Here's the weird global control registers which are said to live
+ * way up here.
+ */
+#define REG_GL_CSR     0x3004  /* Control/status register */
+#define   GCSR_SRS      0x00000001     /* SW Reset set */
+#define   GCSR_SRC      0x00000002     /* SW Reset clear */
+#define          GCSR_MRS       0x00000004     /* Master reset set */
+#define          GCSR_MRC       0x00000008     /* HW Reset clear */
+#define   GCSR_CCIC_EN   0x00004000    /* CCIC Clock enable */
+#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
+#define   GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
+
+#define REG_LEN                REG_GL_IMASK + 4
+
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
new file mode 100644 (file)
index 0000000..e347c7e
--- /dev/null
@@ -0,0 +1,2228 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip.  Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#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>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "cafe_ccic-regs.h"
+
+#define CAFE_VERSION 0x000001
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+/*
+ * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers.  We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+#define MAX_DMA_BUFS 3
+static int alloc_bufs_at_load = 0;
+module_param(alloc_bufs_at_load, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_load,
+               "Non-zero value causes DMA buffers to be allocated at module "
+               "load time.  This increases the chances of successfully getting "
+               "those buffers, but at the cost of nailing down the memory from "
+               "the outset.");
+
+static int n_dma_bufs = 3;
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+               "The number of DMA buffers to allocate.  Can be either two "
+               "(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+               "The size of the allocated DMA buffers.  If actual operating "
+               "parameters require larger buffers, an attempt to reallocate "
+               "will be made.");
+
+static int min_buffers = 1;
+module_param(min_buffers, uint, 0644);
+MODULE_PARM_DESC(min_buffers,
+               "The minimum number of streaming I/O buffers we are willing "
+               "to work with.");
+
+static int max_buffers = 10;
+module_param(max_buffers, uint, 0644);
+MODULE_PARM_DESC(max_buffers,
+               "The maximum number of streaming I/O buffers an application "
+               "will be allowed to allocate.  These buffers are big and live "
+               "in vmalloc space.");
+
+static int flip = 0;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+               "If set, the sensor will be instructed to flip the image "
+               "vertically.");
+
+
+enum cafe_state {
+       S_NOTREADY,     /* Not yet initialized */
+       S_IDLE,         /* Just hanging around */
+       S_FLAKED,       /* Some sort of problem */
+       S_SINGLEREAD,   /* In read() */
+       S_SPECREAD,     /* Speculative read (for future read()) */
+       S_STREAMING     /* Streaming data */
+};
+
+/*
+ * Tracking of streaming I/O buffers.
+ */
+struct cafe_sio_buffer {
+       struct list_head list;
+       struct v4l2_buffer v4lbuf;
+       char *buffer;   /* Where it lives in kernel space */
+       int mapcount;
+       struct cafe_camera *cam;
+};
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex.  Certain fields, however, require
+ *         the dev_lock spinlock; they are marked as such by comments.
+ *         dev_lock is also required for access to device registers.
+ */
+struct cafe_camera
+{
+       enum cafe_state state;
+       unsigned long flags;            /* Buffer status, mainly (dev_lock) */
+       int users;                      /* How many open FDs */
+       struct file *owner;             /* Who has data access (v4l2) */
+
+       /*
+        * Subsystem structures.
+        */
+       struct pci_dev *pdev;
+       struct video_device v4ldev;
+       struct i2c_adapter i2c_adapter;
+       struct i2c_client *sensor;
+
+       unsigned char __iomem *regs;
+       struct list_head dev_list;      /* link to other devices */
+
+       /* DMA buffers */
+       unsigned int nbufs;             /* How many are alloc'd */
+       int next_buf;                   /* Next to consume (dev_lock) */
+       unsigned int dma_buf_size;      /* allocated size */
+       void *dma_bufs[MAX_DMA_BUFS];   /* Internal buffer addresses */
+       dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+       unsigned int specframes;        /* Unconsumed spec frames (dev_lock) */
+       unsigned int sequence;          /* Frame sequence number */
+       unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
+
+       /* Streaming buffers */
+       unsigned int n_sbufs;           /* How many we have */
+       struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
+       struct list_head sb_avail;      /* Available for data (we own) (dev_lock) */
+       struct list_head sb_full;       /* With data (user space owns) (dev_lock) */
+       struct tasklet_struct s_tasklet;
+
+       /* Current operating parameters */
+       enum v4l2_chip_ident sensor_type;               /* Currently ov7670 only */
+       struct v4l2_pix_format pix_format;
+
+       /* Locks */
+       struct mutex s_mutex; /* Access to this structure */
+       spinlock_t dev_lock;  /* Access to device */
+
+       /* 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
+};
+
+/*
+ * Status flags.  Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID   0      /* Buffers valid - first three */
+#define CF_BUF1_VALID   1
+#define CF_BUF2_VALID   2
+#define CF_DMA_ACTIVE   3      /* A frame is incoming */
+#define CF_CONFIG_NEEDED 4     /* Must configure hardware */
+
+
+
+/*
+ * Start over with DMA buffers - dev_lock needed.
+ */
+static void cafe_reset_buffers(struct cafe_camera *cam)
+{
+       int i;
+
+       cam->next_buf = -1;
+       for (i = 0; i < cam->nbufs; i++)
+               clear_bit(i, &cam->flags);
+       cam->specframes = 0;
+}
+
+static inline int cafe_needs_config(struct cafe_camera *cam)
+{
+       return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
+{
+       if (needed)
+               set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       else
+               clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+       dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
+
+
+/* ---------------------------------------------------------------------*/
+/*
+ * 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
+ */
+static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
+               unsigned int val)
+{
+       iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
+               unsigned int reg)
+{
+       return ioread32(cam->regs + reg);
+}
+
+
+static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
+               unsigned int val, unsigned int mask)
+{
+       unsigned int v = cafe_reg_read(cam, reg);
+
+       v = (v & ~mask) | (val & mask);
+       cafe_reg_write(cam, reg, v);
+}
+
+static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       cafe_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void cafe_reg_set_bit(struct cafe_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       cafe_reg_write_mask(cam, reg, val, val);
+}
+
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here.  The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
+
+static int cafe_smbus_write_done(struct cafe_camera *cam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       c1 = cafe_reg_read(cam, REG_TWSIC1);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 value)
+{
+       unsigned int rval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
+       /*
+        * Marvell sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       cafe_reg_write(cam, REG_TWSIC0, rval);
+       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+       rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       cafe_reg_write(cam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       msleep(2); /* Required or things flake */
+
+       wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
+                       CAFE_SMBUS_TIMEOUT);
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       rval = cafe_reg_read(cam, REG_TWSIC1);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+       if (rval & TWSIC1_WSTAT) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct cafe_camera *cam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       c1 = cafe_reg_read(cam, REG_TWSIC1);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 *value)
+{
+       unsigned int rval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+       /*
+        * Marvel sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       cafe_reg_write(cam, REG_TWSIC0, rval);
+       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+       rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       cafe_reg_write(cam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+       wait_event_timeout(cam->smbus_wait,
+                       cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       rval = cafe_reg_read(cam, REG_TWSIC1);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+               return -EIO;
+       }
+       if (! (rval & TWSIC1_RVALID)) {
+               cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+                               command);
+               return -EIO;
+       }
+       *value = rval & 0xff;
+       return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS.  This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+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);
+       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.
+        */
+       if (size != I2C_SMBUS_BYTE_DATA) {
+               cam_err(cam, "funky xfer size %d\n", size);
+               return -EINVAL;
+       }
+
+       if (rw == I2C_SMBUS_WRITE)
+               ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+       else if (rw == I2C_SMBUS_READ)
+               ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+       return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+       .smbus_xfer = cafe_smbus_xfer,
+       .functionality = cafe_smbus_func
+};
+
+/* 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;
+       int ret;
+
+       cafe_smbus_enable_irq(cam);
+       adap->id = I2C_HW_SMBUS_CAFE;
+       adap->class = I2C_CLASS_CAM_DIGITAL;
+       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");
+       i2c_set_adapdata(adap, cam);
+       ret = i2c_add_adapter(adap);
+       if (ret)
+               printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+       return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+       i2c_del_adapter(&cam->i2c_adapter);
+}
+
+
+/* ------------------------------------------------------------------- */
+/*
+ * Deal with the controller.
+ */
+
+/*
+ * Do everything we think we need to have the interface operating
+ * according to the desired format.
+ */
+static void cafe_ctlr_dma(struct cafe_camera *cam)
+{
+       /*
+        * Store the first two Y buffers (we aren't supporting
+        * planar formats for now, so no UV bufs).  Then either
+        * set the third if it exists, or tell the controller
+        * to just use two.
+        */
+       cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+       cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+       if (cam->nbufs > 2) {
+               cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+               cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       }
+       else
+               cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
+}
+
+static void cafe_ctlr_image(struct cafe_camera *cam)
+{
+       int imgsz;
+       struct v4l2_pix_format *fmt = &cam->pix_format;
+
+       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+               (fmt->bytesperline & IMGSZ_H_MASK);
+       cafe_reg_write(cam, REG_IMGSIZE, imgsz);
+       cafe_reg_write(cam, REG_IMGOFFSET, 0);
+       /* YPITCH just drops the last two bits */
+       cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+                       IMGP_YP_MASK);
+       /*
+        * Tell the controller about the image format we are using.
+        */
+       switch (cam->pix_format.pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+           cafe_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+                           C0_DF_MASK);
+           break;
+
+       case V4L2_PIX_FMT_RGB444:
+           cafe_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+                           C0_DF_MASK);
+               /* Alpha value? */
+           break;
+
+       case V4L2_PIX_FMT_RGB565:
+           cafe_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+                           C0_DF_MASK);
+           break;
+
+       default:
+           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+           break;
+       }
+       /*
+        * Make sure it knows we want to use hsync/vsync.
+        */
+       cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+                       C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int cafe_ctlr_configure(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_ctlr_dma(cam);
+       cafe_ctlr_image(cam);
+       cafe_set_config_needed(cam, 0);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
+{
+       /*
+        * Clear any pending interrupts, since we do not
+        * expect to have I/O active prior to enabling.
+        */
+       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+       cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
+{
+       cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+/*
+ * Make the controller start grabbing images.  Everything must
+ * be set up before doing this.
+ */
+static void cafe_ctlr_start(struct cafe_camera *cam)
+{
+       /* set_bit performs a read, so no other barrier should be
+          needed here */
+       cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_stop(struct cafe_camera *cam)
+{
+       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_init(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       /*
+        * Added magic to bring up the hardware on the B-Test board
+        */
+       cafe_reg_write(cam, 0x3038, 0x8);
+       cafe_reg_write(cam, 0x315c, 0x80008);
+       /*
+        * Go through the dance needed to wake the device up.
+        * Note that these registers are global and shared
+        * with the NAND and SD devices.  Interaction between the
+        * three still needs to be examined.
+        */
+       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+       mdelay(5);      /* FIXME revisit this */
+       cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+       cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
+       /*
+        * Make sure it's not powered down.
+        */
+       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       /*
+        * Turn off the enable bit.  It sure should be off anyway,
+        * but it's good to be sure.
+        */
+       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+       /*
+        * Mask all interrupts.
+        */
+       cafe_reg_write(cam, REG_IRQMASK, 0);
+       /*
+        * Clock the sensor appropriately.  Controller clock should
+        * be 48MHz, sensor "typical" value is half that.
+        */
+       cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       /*
+        * Theory: stop the camera controller (whether it is operating
+        * or not).  Delay briefly just in case we race with the SOF
+        * interrupt, then wait until no DMA is active.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_ctlr_stop(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       mdelay(1);
+       wait_event_timeout(cam->iowait,
+                       !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
+       if (test_bit(CF_DMA_ACTIVE, &cam->flags))
+               cam_err(cam, "Timeout waiting for DMA to end\n");
+               /* This would be bad news - what now? */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cam->state = S_IDLE;
+       cafe_ctlr_irq_disable(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void cafe_ctlr_power_up(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       /*
+        * Put the sensor into operational mode (assumes OLPC-style
+        * wiring).  Control 0 is reset - set to 1 to operate.
+        * 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 */
+       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+       mdelay(1); /* Enough? */
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static void cafe_ctlr_power_down(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+       cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * 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);
+}
+
+/*
+ * We have found the sensor on the i2c.  Let's try to have a
+ * conversation.
+ */
+static int cafe_cam_init(struct cafe_camera *cam)
+{
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->state != S_NOTREADY)
+               cam_warn(cam, "Cam init with device in funky state %d",
+                               cam->state);
+       ret = __cafe_cam_reset(cam);
+       if (ret)
+               goto out;
+       ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
+       if (ret)
+               goto out;
+//     if (cam->sensor->addr != OV7xx0_SID) {
+       if (cam->sensor_type != V4L2_IDENT_OV7670) {
+               cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
+               ret = -EINVAL;
+               goto out;
+       }
+/* Get/set parameters? */
+       ret = 0;
+       cam->state = S_IDLE;
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have.  Caller should
+ * hold s_mutex
+ */
+static int cafe_cam_set_flip(struct cafe_camera *cam)
+{
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = V4L2_CID_VFLIP;
+       ctrl.value = flip;
+       return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
+}
+
+
+static int cafe_cam_configure(struct cafe_camera *cam)
+{
+       struct v4l2_format fmt;
+       int ret, zero = 0;
+
+       if (cam->state != S_IDLE)
+               return -EINVAL;
+       fmt.fmt.pix = cam->pix_format;
+       ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
+       if (ret == 0)
+               ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
+       /*
+        * OV7670 does weird things if flip is set *before* format...
+        */
+       ret += cafe_cam_set_flip(cam);
+       return ret;
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * DMA buffer management.  These functions need s_mutex held.
+ */
+
+/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
+ * does a get_free_pages() call, and we waste a good chunk of an orderN
+ * allocation.  Should try to allocate the whole set in one chunk.
+ */
+static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
+{
+       int i;
+
+       cafe_set_config_needed(cam, 1);
+       if (loadtime)
+               cam->dma_buf_size = dma_buf_size;
+       else
+               cam->dma_buf_size = cam->pix_format.sizeimage;
+       if (n_dma_bufs > 3)
+               n_dma_bufs = 3;
+
+       cam->nbufs = 0;
+       for (i = 0; i < n_dma_bufs; i++) {
+               cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
+                               cam->dma_buf_size, cam->dma_handles + i,
+                               GFP_KERNEL);
+               if (cam->dma_bufs[i] == NULL) {
+                       cam_warn(cam, "Failed to allocate DMA buffer\n");
+                       break;
+               }
+               /* For debug, remove eventually */
+               memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
+               (cam->nbufs)++;
+       }
+
+       switch (cam->nbufs) {
+       case 1:
+           dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+                           cam->dma_bufs[0], cam->dma_handles[0]);
+           cam->nbufs = 0;
+       case 0:
+           cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+           return -ENOMEM;
+
+       case 2:
+           if (n_dma_bufs > 2)
+                   cam_warn(cam, "Will limp along with only 2 buffers\n");
+           break;
+       }
+       return 0;
+}
+
+static void cafe_free_dma_bufs(struct cafe_camera *cam)
+{
+       int i;
+
+       for (i = 0; i < cam->nbufs; i++) {
+               dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+                               cam->dma_bufs[i], cam->dma_handles[i]);
+               cam->dma_bufs[i] = NULL;
+       }
+       cam->nbufs = 0;
+}
+
+
+
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Here starts the V4L2 interface code.
+ */
+
+/*
+ * Read an image from the device.
+ */
+static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
+               char __user *buffer, size_t len, loff_t *pos)
+{
+       int bufno;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       if (cam->next_buf < 0) {
+               cam_err(cam, "deliver_buffer: No next buffer\n");
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
+               return -EIO;
+       }
+       bufno = cam->next_buf;
+       clear_bit(bufno, &cam->flags);
+       if (++(cam->next_buf) >= cam->nbufs)
+               cam->next_buf = 0;
+       if (! test_bit(cam->next_buf, &cam->flags))
+               cam->next_buf = -1;
+       cam->specframes = 0;
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+       if (len > cam->pix_format.sizeimage)
+               len = cam->pix_format.sizeimage;
+       if (copy_to_user(buffer, cam->dma_bufs[bufno], len))
+               return -EFAULT;
+       (*pos) += len;
+       return len;
+}
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
+{
+       int ret;
+       unsigned long flags;
+
+       /*
+        * Configuration.  If we still don't have DMA buffers,
+        * make one last, desperate attempt.
+        */
+       if (cam->nbufs == 0)
+               if (cafe_alloc_dma_bufs(cam, 0))
+                       return -ENOMEM;
+
+       if (cafe_needs_config(cam)) {
+               cafe_cam_configure(cam);
+               ret = cafe_ctlr_configure(cam);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Turn it loose.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cafe_reset_buffers(cam);
+       cafe_ctlr_irq_enable(cam);
+       cam->state = state;
+       cafe_ctlr_start(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+
+static ssize_t cafe_v4l_read(struct file *filp,
+               char __user *buffer, size_t len, loff_t *pos)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret;
+
+       /*
+        * Perhaps we're in speculative read mode and already
+        * have data?
+        */
+       mutex_lock(&cam->s_mutex);
+       if (cam->state == S_SPECREAD) {
+               if (cam->next_buf >= 0) {
+                       ret = cafe_deliver_buffer(cam, buffer, len, pos);
+                       if (ret != 0)
+                               goto out_unlock;
+               }
+       } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
+               ret = -EIO;
+               goto out_unlock;
+       } else if (cam->state != S_IDLE) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       /*
+        * v4l2: multiple processes can open the device, but only
+        * one gets to grab data from it.
+        */
+       if (cam->owner && cam->owner != filp) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       cam->owner = filp;
+
+       /*
+        * Do setup if need be.
+        */
+       if (cam->state != S_SPECREAD) {
+               ret = cafe_read_setup(cam, S_SINGLEREAD);
+               if (ret)
+                       goto out_unlock;
+       }
+       /*
+        * Wait for something to happen.  This should probably
+        * be interruptible (FIXME).
+        */
+       wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
+       if (cam->next_buf < 0) {
+               cam_err(cam, "read() operation timed out\n");
+               cafe_ctlr_stop_dma(cam);
+               ret = -EIO;
+               goto out_unlock;
+       }
+       /*
+        * Give them their data and we should be done.
+        */
+       ret = cafe_deliver_buffer(cam, buffer, len, pos);
+
+  out_unlock:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+
+
+
+
+
+/*
+ * Streaming I/O support.
+ */
+
+
+
+static int cafe_vidioc_streamon(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret = -EINVAL;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               goto out;
+       mutex_lock(&cam->s_mutex);
+       if (cam->state != S_IDLE || cam->n_sbufs == 0)
+               goto out_unlock;
+
+       cam->sequence = 0;
+       ret = cafe_read_setup(cam, S_STREAMING);
+
+  out_unlock:
+       mutex_unlock(&cam->s_mutex);
+  out:
+       return ret;
+}
+
+
+static int cafe_vidioc_streamoff(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret = -EINVAL;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               goto out;
+       mutex_lock(&cam->s_mutex);
+       if (cam->state != S_STREAMING)
+               goto out_unlock;
+
+       cafe_ctlr_stop_dma(cam);
+       ret = 0;
+
+  out_unlock:
+       mutex_unlock(&cam->s_mutex);
+  out:
+       return ret;
+}
+
+
+
+static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
+{
+       struct cafe_sio_buffer *buf = cam->sb_bufs + index;
+
+       INIT_LIST_HEAD(&buf->list);
+       buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
+       buf->buffer = vmalloc_user(buf->v4lbuf.length);
+       if (buf->buffer == NULL)
+               return -ENOMEM;
+       buf->mapcount = 0;
+       buf->cam = cam;
+
+       buf->v4lbuf.index = index;
+       buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       buf->v4lbuf.field = V4L2_FIELD_NONE;
+       buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
+       /*
+        * Offset: must be 32-bit even on a 64-bit system.  video-buf
+        * just uses the length times the index, but the spec warns
+        * against doing just that - vma merging problems.  So we
+        * leave a gap between each pair of buffers.
+        */
+       buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
+       return 0;
+}
+
+static int cafe_free_sio_buffers(struct cafe_camera *cam)
+{
+       int i;
+
+       /*
+        * If any buffers are mapped, we cannot free them at all.
+        */
+       for (i = 0; i < cam->n_sbufs; i++)
+               if (cam->sb_bufs[i].mapcount > 0)
+                       return -EBUSY;
+       /*
+        * OK, let's do it.
+        */
+       for (i = 0; i < cam->n_sbufs; i++)
+               vfree(cam->sb_bufs[i].buffer);
+       cam->n_sbufs = 0;
+       kfree(cam->sb_bufs);
+       cam->sb_bufs = NULL;
+       INIT_LIST_HEAD(&cam->sb_avail);
+       INIT_LIST_HEAD(&cam->sb_full);
+       return 0;
+}
+
+
+
+static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
+               struct v4l2_requestbuffers *req)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret;
+
+       /*
+        * 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;
+       /*
+        * If they ask for zero buffers, they really want us to stop streaming
+        * (if it's happening) and free everything.  Should we check owner?
+        */
+       mutex_lock(&cam->s_mutex);
+       if (req->count == 0) {
+               if (cam->state == S_STREAMING)
+                       cafe_ctlr_stop_dma(cam);
+               ret = cafe_free_sio_buffers (cam);
+               goto out;
+       }
+       /*
+        * Device needs to be idle and working.  We *could* try to do the
+        * right thing in S_SPECREAD by shutting things down, but it
+        * probably doesn't matter.
+        */
+       if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       cam->owner = filp;
+
+       if (req->count < min_buffers)
+               req->count = min_buffers;
+       else if (req->count > max_buffers)
+               req->count = max_buffers;
+       if (cam->n_sbufs > 0) {
+               ret = cafe_free_sio_buffers(cam);
+               if (ret)
+                       goto out;
+       }
+
+       cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
+                       GFP_KERNEL);
+       if (cam->sb_bufs == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
+               ret = cafe_setup_siobuf(cam, cam->n_sbufs);
+               if (ret)
+                       break;
+       }
+
+       if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
+               kfree(cam->sb_bufs);
+       else
+               ret = 0;
+       req->count = cam->n_sbufs;  /* In case of partial success */
+
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int cafe_vidioc_querybuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct cafe_camera *cam = filp->private_data;
+       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)
+               goto out;
+       *buf = cam->sb_bufs[buf->index].v4lbuf;
+       ret = 0;
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int cafe_vidioc_qbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct cafe_camera *cam = filp->private_data;
+       struct cafe_sio_buffer *sbuf;
+       int ret = -EINVAL;
+       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)
+               goto out;
+       sbuf = cam->sb_bufs + buf->index;
+       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
+               ret = 0; /* Already queued?? */
+               goto out;
+       }
+       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
+               /* Spec doesn't say anything, seems appropriate tho */
+               ret = -EBUSY;
+               goto out;
+       }
+       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       list_add(&sbuf->list, &cam->sb_avail);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       ret = 0;
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct cafe_camera *cam = filp->private_data;
+       struct cafe_sio_buffer *sbuf;
+       int ret = -EINVAL;
+       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) {
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
+
+       while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
+               mutex_unlock(&cam->s_mutex);
+               if (wait_event_interruptible(cam->iowait,
+                                               !list_empty(&cam->sb_full))) {
+                       ret = -ERESTARTSYS;
+                       goto out;
+               }
+               mutex_lock(&cam->s_mutex);
+       }
+
+       if (cam->state != S_STREAMING)
+               ret = -EINTR;
+       else {
+               spin_lock_irqsave(&cam->dev_lock, flags);
+               /* Should probably recheck !list_empty() here */
+               sbuf = list_entry(cam->sb_full.next,
+                               struct cafe_sio_buffer, list);
+               list_del_init(&sbuf->list);
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
+               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
+               *buf = sbuf->v4lbuf;
+               ret = 0;
+       }
+
+  out_unlock:
+       mutex_unlock(&cam->s_mutex);
+  out:
+       return ret;
+}
+
+
+
+static void cafe_v4l_vm_open(struct vm_area_struct *vma)
+{
+       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+       /*
+        * Locking: done under mmap_sem, so we don't need to
+        * go back to the camera lock here.
+        */
+       sbuf->mapcount++;
+}
+
+
+static void cafe_v4l_vm_close(struct vm_area_struct *vma)
+{
+       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+
+       mutex_lock(&sbuf->cam->s_mutex);
+       sbuf->mapcount--;
+       /* Docs say we should stop I/O too... */
+       if (sbuf->mapcount == 0)
+               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+       mutex_unlock(&sbuf->cam->s_mutex);
+}
+
+static struct vm_operations_struct cafe_v4l_vm_ops = {
+       .open = cafe_v4l_vm_open,
+       .close = cafe_v4l_vm_close
+};
+
+
+static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct cafe_camera *cam = filp->private_data;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int ret = -EINVAL;
+       int i;
+       struct cafe_sio_buffer *sbuf = NULL;
+
+       if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+       /*
+        * Find the buffer they are looking for.
+        */
+       mutex_lock(&cam->s_mutex);
+       for (i = 0; i < cam->n_sbufs; i++)
+               if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
+                       sbuf = cam->sb_bufs + i;
+                       break;
+               }
+       if (sbuf == NULL)
+               goto out;
+
+       ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
+       if (ret)
+               goto out;
+       vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_private_data = sbuf;
+       vma->vm_ops = &cafe_v4l_vm_ops;
+       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
+       cafe_v4l_vm_open(vma);
+       ret = 0;
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static int cafe_v4l_open(struct inode *inode, struct file *filp)
+{
+       struct cafe_camera *cam;
+
+       cam = cafe_find_dev(iminor(inode));
+       if (cam == NULL)
+               return -ENODEV;
+       filp->private_data = cam;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->users == 0) {
+               cafe_ctlr_power_up(cam);
+               __cafe_cam_reset(cam);
+               cafe_set_config_needed(cam, 1);
+       /* FIXME make sure this is complete */
+       }
+       (cam->users)++;
+       mutex_unlock(&cam->s_mutex);
+       return 0;
+}
+
+
+static int cafe_v4l_release(struct inode *inode, struct file *filp)
+{
+       struct cafe_camera *cam = filp->private_data;
+
+       mutex_lock(&cam->s_mutex);
+       (cam->users)--;
+       if (filp == cam->owner) {
+               cafe_ctlr_stop_dma(cam);
+               cafe_free_sio_buffers(cam);
+               cam->owner = NULL;
+       }
+       if (cam->users == 0) {
+               cafe_ctlr_power_down(cam);
+               if (! alloc_bufs_at_load)
+                       cafe_free_dma_bufs(cam);
+       }
+       mutex_unlock(&cam->s_mutex);
+       return 0;
+}
+
+
+
+static unsigned int cafe_v4l_poll(struct file *filp,
+               struct poll_table_struct *pt)
+{
+       struct cafe_camera *cam = filp->private_data;
+
+       poll_wait(filp, &cam->iowait, pt);
+       if (cam->next_buf >= 0)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+
+
+static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct cafe_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+
+
+static int cafe_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "cafe_ccic");
+       strcpy(cap->card, "cafe_ccic");
+       cap->version = CAFE_VERSION;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static struct v4l2_pix_format cafe_def_pix_format = {
+       .width          = VGA_WIDTH,
+       .height         = VGA_HEIGHT,
+       .pixelformat    = V4L2_PIX_FMT_YUYV,
+       .field          = V4L2_FIELD_NONE,
+       .bytesperline   = VGA_WIDTH*2,
+       .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+               void *priv, struct v4l2_fmtdesc *fmt)
+{
+       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);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       /*
+        * Can't do anything if the device is not idle
+        * Also can't if there are streaming buffers in place.
+        */
+       if (cam->state != S_IDLE || cam->n_sbufs > 0)
+               return -EBUSY;
+       /*
+        * See if the formatting works in principle.
+        */
+       ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+       if (ret)
+               return ret;
+       /*
+        * Now we start to change things for real, so let's do it
+        * under lock.
+        */
+       mutex_lock(&cam->s_mutex);
+       cam->pix_format = fmt->fmt.pix;
+       /*
+        * Make sure we have appropriate DMA buffers.
+        */
+       ret = -ENOMEM;
+       if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+               cafe_free_dma_bufs(cam);
+       if (cam->nbufs == 0) {
+               if (cafe_alloc_dma_bufs(cam, 0))
+                       goto out;
+       }
+       /*
+        * It looks like this might work, so let's program the sensor.
+        */
+       ret = cafe_cam_configure(cam);
+       if (! ret)
+               ret = cafe_ctlr_configure(cam);
+  out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time).  Someday.
+ */
+static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+               struct v4l2_format *f)
+{
+       struct cafe_camera *cam = priv;
+
+       f->fmt.pix = cam->pix_format;
+       return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int cafe_vidioc_enum_input(struct file *filp, void *priv,
+               struct v4l2_input *input)
+{
+       if (input->index != 0)
+               return -EINVAL;
+
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       input->std = V4L2_STD_ALL; /* Not sure what should go here */
+       strcpy(input->name, "Camera");
+       return 0;
+}
+
+static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* from vivi.c */
+static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+       return 0;
+}
+
+/*
+ * G/S_PARM.  Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int cafe_vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int cafe_vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+
+static void cafe_v4l_dev_release(struct video_device *vd)
+{
+       struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
+
+       kfree(cam);
+}
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+
+static struct file_operations cafe_v4l_fops = {
+       .owner = THIS_MODULE,
+       .open = cafe_v4l_open,
+       .release = cafe_v4l_release,
+       .read = cafe_v4l_read,
+       .poll = cafe_v4l_poll,
+       .mmap = cafe_v4l_mmap,
+       .ioctl = video_ioctl2,
+       .llseek = no_llseek,
+};
+
+static struct video_device cafe_v4l_template = {
+       .name = "cafe",
+       .type = VFL_TYPE_GRABBER,
+       .type2 = VID_TYPE_CAPTURE,
+       .minor = -1, /* Get one dynamically */
+       .tvnorms = V4L2_STD_NTSC_M,
+       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
+
+       .fops = &cafe_v4l_fops,
+       .release = cafe_v4l_dev_release,
+
+       .vidioc_querycap        = cafe_vidioc_querycap,
+       .vidioc_enum_fmt_cap    = cafe_vidioc_enum_fmt_cap,
+       .vidioc_try_fmt_cap     = cafe_vidioc_try_fmt_cap,
+       .vidioc_s_fmt_cap       = cafe_vidioc_s_fmt_cap,
+       .vidioc_g_fmt_cap       = cafe_vidioc_g_fmt_cap,
+       .vidioc_enum_input      = cafe_vidioc_enum_input,
+       .vidioc_g_input         = cafe_vidioc_g_input,
+       .vidioc_s_input         = cafe_vidioc_s_input,
+       .vidioc_s_std           = cafe_vidioc_s_std,
+       .vidioc_reqbufs         = cafe_vidioc_reqbufs,
+       .vidioc_querybuf        = cafe_vidioc_querybuf,
+       .vidioc_qbuf            = cafe_vidioc_qbuf,
+       .vidioc_dqbuf           = cafe_vidioc_dqbuf,
+       .vidioc_streamon        = cafe_vidioc_streamon,
+       .vidioc_streamoff       = cafe_vidioc_streamoff,
+       .vidioc_queryctrl       = cafe_vidioc_queryctrl,
+       .vidioc_g_ctrl          = cafe_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
+       .vidioc_g_parm          = cafe_vidioc_g_parm,
+       .vidioc_s_parm          = cafe_vidioc_s_parm,
+};
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+
+
+
+static void cafe_frame_tasklet(unsigned long data)
+{
+       struct cafe_camera *cam = (struct cafe_camera *) data;
+       int i;
+       unsigned long flags;
+       struct cafe_sio_buffer *sbuf;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       for (i = 0; i < cam->nbufs; i++) {
+               int bufno = cam->next_buf;
+               if (bufno < 0) {  /* "will never happen" */
+                       cam_err(cam, "No valid bufs in tasklet!\n");
+                       break;
+               }
+               if (++(cam->next_buf) >= cam->nbufs)
+                       cam->next_buf = 0;
+               if (! test_bit(bufno, &cam->flags))
+                       continue;
+               if (list_empty(&cam->sb_avail))
+                       break;  /* Leave it valid, hope for better later */
+               clear_bit(bufno, &cam->flags);
+               /*
+                * We could perhaps drop the spinlock during this
+                * big copy.  Something to consider.
+                */
+               sbuf = list_entry(cam->sb_avail.next,
+                               struct cafe_sio_buffer, list);
+               memcpy(sbuf->buffer, cam->dma_bufs[bufno],
+                               cam->pix_format.sizeimage);
+               sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
+               sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
+               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+               sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+               list_move_tail(&sbuf->list, &cam->sb_full);
+       }
+       if (! list_empty(&cam->sb_full))
+               wake_up(&cam->iowait);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+
+static void cafe_frame_complete(struct cafe_camera *cam, int frame)
+{
+       /*
+        * Basic frame housekeeping.
+        */
+       if (test_bit(frame, &cam->flags) && printk_ratelimit())
+               cam_err(cam, "Frame overrun on %d, frames lost\n", frame);
+       set_bit(frame, &cam->flags);
+       clear_bit(CF_DMA_ACTIVE, &cam->flags);
+       if (cam->next_buf < 0)
+               cam->next_buf = frame;
+       cam->buf_seq[frame] = ++(cam->sequence);
+
+       switch (cam->state) {
+       /*
+        * If in single read mode, try going speculative.
+        */
+           case S_SINGLEREAD:
+               cam->state = S_SPECREAD;
+               cam->specframes = 0;
+               wake_up(&cam->iowait);
+               break;
+
+       /*
+        * If we are already doing speculative reads, and nobody is
+        * reading them, just stop.
+        */
+           case S_SPECREAD:
+               if (++(cam->specframes) >= cam->nbufs) {
+                       cafe_ctlr_stop(cam);
+                       cafe_ctlr_irq_disable(cam);
+                       cam->state = S_IDLE;
+               }
+               wake_up(&cam->iowait);
+               break;
+       /*
+        * For the streaming case, we defer the real work to the
+        * camera tasklet.
+        *
+        * FIXME: if the application is not consuming the buffers,
+        * we should eventually put things on hold and restart in
+        * vidioc_dqbuf().
+        */
+           case S_STREAMING:
+               tasklet_schedule(&cam->s_tasklet);
+               break;
+
+           default:
+               cam_err(cam, "Frame interrupt in non-operational state\n");
+               break;
+       }
+}
+
+
+
+
+static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
+{
+       unsigned int frame;
+
+       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+       /*
+        * Handle any frame completions.  There really should
+        * not be more than one of these, or we have fallen
+        * far behind.
+        */
+       for (frame = 0; frame < cam->nbufs; frame++)
+               if (irqs & (IRQ_EOF0 << frame))
+                       cafe_frame_complete(cam, frame);
+       /*
+        * If a frame starts, note that we have DMA active.  This
+        * code assumes that we won't get multiple frame interrupts
+        * at once; may want to rethink that.
+        */
+       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
+               set_bit(CF_DMA_ACTIVE, &cam->flags);
+}
+
+
+
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+       struct cafe_camera *cam = data;
+       unsigned int irqs;
+
+       spin_lock(&cam->dev_lock);
+       irqs = cafe_reg_read(cam, REG_IRQSTAT);
+       if ((irqs & ALLIRQS) == 0) {
+               spin_unlock(&cam->dev_lock);
+               return IRQ_NONE;
+       }
+       if (irqs & FRAMEIRQS)
+               cafe_frame_irq(cam, irqs);
+       if (irqs & TWSIIRQS) {
+               cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
+               wake_up(&cam->smbus_wait);
+       }
+       spin_unlock(&cam->dev_lock);
+       return IRQ_HANDLED;
+}
+
+
+/* -------------------------------------------------------------------------- */
+#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 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 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.minor);
+       cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+                       cam, &cafe_dfs_reg_ops);
+       sprintf(fname, "cam-%d", cam->v4ldev.minor);
+       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.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       int ret;
+       u16 classword;
+       struct cafe_camera *cam;
+       /*
+        * Make sure we have a camera here - we'll get calls for
+        * the other cafe devices as well.
+        */
+       pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
+       if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
+               return -ENODEV;
+       /*
+        * Start putting together one of our big camera structures.
+        */
+       ret = -ENOMEM;
+       cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+       if (cam == NULL)
+               goto out;
+       mutex_init(&cam->s_mutex);
+       mutex_lock(&cam->s_mutex);
+       spin_lock_init(&cam->dev_lock);
+       cam->state = S_NOTREADY;
+       cafe_set_config_needed(cam, 1);
+       init_waitqueue_head(&cam->smbus_wait);
+       init_waitqueue_head(&cam->iowait);
+       cam->pdev = pdev;
+       cam->pix_format = cafe_def_pix_format;
+       INIT_LIST_HEAD(&cam->dev_list);
+       INIT_LIST_HEAD(&cam->sb_avail);
+       INIT_LIST_HEAD(&cam->sb_full);
+       tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
+       /*
+        * Get set up on the PCI bus.
+        */
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto out_free;
+       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;
+       }
+       ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+       if (ret)
+               goto out_iounmap;
+       cafe_ctlr_init(cam);
+       cafe_ctlr_power_up(cam);
+       /*
+        * Set up I2C/SMBUS communications
+        */
+       mutex_unlock(&cam->s_mutex);  /* attach can deadlock */
+       ret = cafe_smbus_setup(cam);
+       if (ret)
+               goto out_freeirq;
+       /*
+        * 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;
+       ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               goto out_smbus;
+       /*
+        * If so requested, try to get our DMA buffers now.
+        */
+       if (alloc_bufs_at_load) {
+               if (cafe_alloc_dma_bufs(cam, 1))
+                       cam_warn(cam, "Unable to alloc DMA buffers at load"
+                                       " will try again later.");
+       }
+
+       cafe_dfs_cam_setup(cam);
+       mutex_unlock(&cam->s_mutex);
+       cafe_add_dev(cam);
+       return 0;
+
+  out_smbus:
+       cafe_smbus_shutdown(cam);
+  out_freeirq:
+       cafe_ctlr_power_down(cam);
+       free_irq(pdev->irq, cam);
+  out_iounmap:
+       pci_iounmap(pdev, cam->regs);
+  out_free:
+       kfree(cam);
+  out:
+       return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+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 () */
+}
+
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+       struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+
+       if (cam == NULL) {
+               cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev);
+               return;
+       }
+       mutex_lock(&cam->s_mutex);
+       if (cam->users > 0)
+               cam_warn(cam, "Removing a device with users!\n");
+       cafe_shutdown(cam);
+/* No unlock - it no longer exists */
+}
+
+
+
+
+static struct pci_device_id cafe_ids[] = {
+       { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
+       { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
+       { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+       .name = "cafe1000-ccic",
+       .id_table = cafe_ids,
+       .probe = cafe_pci_probe,
+       .remove = cafe_pci_remove,
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+       int ret;
+
+       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:
+       return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+       pci_unregister_driver(&cafe_pci_driver);
+       cafe_dfs_shutdown();
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
index 0f9d96963618221fbf8ef43f8b298e00f92e0e95..b2a66ba625f99505f88ec1c04189cecc2d602c95 100644 (file)
@@ -53,6 +53,7 @@ config VIDEO_CX88_DVB
        select DVB_OR51132 if !DVB_FE_CUSTOMISE
        select DVB_CX22702 if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
        select DVB_NXT200X if !DVB_FE_CUSTOMISE
        select DVB_CX24123 if !DVB_FE_CUSTOMISE
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
index 46738321adafe22367e319c205adf24054fee166..0cf0360588e6c8d30e562f7945f3a5bdd263d143 100644 (file)
@@ -50,7 +50,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
 #define dprintk(level,fmt, arg...)     if (debug >= level) \
        printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg)
 
-static LIST_HEAD(cx8802_devlist);
 
 /* ------------------------------------------------------------------ */
 
@@ -882,7 +881,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
                                  BLACKBIRD_MPEG_CAPTURE,
                                  BLACKBIRD_RAW_BITS_NONE);
 
-               cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+               cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
 
                blackbird_initialize_codec(dev);
                cx88_set_scale(dev->core, dev->width, dev->height,
@@ -914,11 +913,15 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
        }
 
        default:
-               return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+               return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
        }
        return 0;
 }
 
+int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
+                       unsigned int cmd, void *arg);
+unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+
 static unsigned int mpeg_translate_ioctl(unsigned int cmd)
 {
        return cmd;
@@ -927,33 +930,49 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd)
 static int mpeg_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
-       cmd = mpeg_translate_ioctl( cmd );
-       return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+       cmd = cx88_ioctl_translator( cmd );
+       return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
 }
 
 static int mpeg_open(struct inode *inode, struct file *file)
 {
        int minor = iminor(inode);
-       struct cx8802_dev *h,*dev = NULL;
+       struct cx8802_dev *dev = NULL;
        struct cx8802_fh *fh;
-       struct list_head *list;
+       struct cx8802_driver *drv = NULL;
+       int err;
 
-       list_for_each(list,&cx8802_devlist) {
-               h = list_entry(list, struct cx8802_dev, devlist);
-               if (h->mpeg_dev->minor == minor)
-                       dev = h;
-       }
-       if (NULL == dev)
+       dev = cx8802_get_device(inode);
+
+       dprintk( 1, "%s\n", __FUNCTION__);
+
+       if (dev == NULL)
                return -ENODEV;
 
-       if (blackbird_initialize_codec(dev) < 0)
+       /* Make sure we can acquire the hardware */
+       drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+       if (drv) {
+               err = drv->request_acquire(drv);
+               if(err != 0) {
+                       dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err);
+                       return err;
+               }
+       }
+
+       if (blackbird_initialize_codec(dev) < 0) {
+               if (drv)
+                       drv->request_release(drv);
                return -EINVAL;
+       }
        dprintk(1,"open minor=%d\n",minor);
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh),GFP_KERNEL);
-       if (NULL == fh)
+       if (NULL == fh) {
+               if (drv)
+                       drv->request_release(drv);
                return -ENOMEM;
+       }
        file->private_data = fh;
        fh->dev      = dev;
 
@@ -974,6 +993,8 @@ static int mpeg_open(struct inode *inode, struct file *file)
 static int mpeg_release(struct inode *inode, struct file *file)
 {
        struct cx8802_fh  *fh  = file->private_data;
+       struct cx8802_dev *dev = NULL;
+       struct cx8802_driver *drv = NULL;
 
        /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
        blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
@@ -992,6 +1013,16 @@ static int mpeg_release(struct inode *inode, struct file *file)
        videobuf_mmap_free(&fh->mpegq);
        file->private_data = NULL;
        kfree(fh);
+
+       /* Make sure we release the hardware */
+       dev = cx8802_get_device(inode);
+       if (dev == NULL)
+               return -ENODEV;
+
+       drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+       if (drv)
+               drv->request_release(drv);
+
        return 0;
 }
 
@@ -1043,6 +1074,44 @@ static struct video_device cx8802_mpeg_template =
 
 /* ------------------------------------------------------------------ */
 
+/* The CX8802 MPEG API will call this when we can use the hardware */
+static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+       int err = 0;
+
+       switch (core->board) {
+       case CX88_BOARD_HAUPPAUGE_HVR1300:
+               /* By default, core setup will leave the cx22702 out of reset, on the bus.
+                * We left the hardware on power up with the cx22702 active.
+                * We're being given access to re-arrange the GPIOs.
+                * Take the bus off the cx22702 and put the cx23416 on it.
+                */
+               cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */
+               cx_set(MO_GP0_IO,   0x00000004); /* Disable the cx22702 */
+               break;
+       default:
+               err = -ENODEV;
+       }
+       return err;
+}
+
+/* The CX8802 MPEG API will call this when we need to release the hardware */
+static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+       int err = 0;
+
+       switch (core->board) {
+       case CX88_BOARD_HAUPPAUGE_HVR1300:
+               /* Exit leaving the cx23416 on the bus */
+               break;
+       default:
+               err = -ENODEV;
+       }
+       return err;
+}
+
 static void blackbird_unregister_video(struct cx8802_dev *dev)
 {
        if (dev->mpeg_dev) {
@@ -1073,28 +1142,23 @@ static int blackbird_register_video(struct cx8802_dev *dev)
 
 /* ----------------------------------------------------------- */
 
-static int __devinit blackbird_probe(struct pci_dev *pci_dev,
-                                    const struct pci_device_id *pci_id)
+static int cx8802_blackbird_probe(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *dev;
-       struct cx88_core  *core;
+       struct cx88_core *core = drv->core;
+       struct cx8802_dev *dev = core->dvbdev;
        int err;
 
-       /* general setup */
-       core = cx88_core_get(pci_dev);
-       if (NULL == core)
-               return -EINVAL;
+       dprintk( 1, "%s\n", __FUNCTION__);
+       dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+               core->board,
+               core->name,
+               core->pci_bus,
+               core->pci_slot);
 
        err = -ENODEV;
        if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
                goto fail_core;
 
-       err = -ENOMEM;
-       dev = kzalloc(sizeof(*dev),GFP_KERNEL);
-       if (NULL == dev)
-               goto fail_core;
-       dev->pci = pci_dev;
-       dev->core = core;
        dev->width = 720;
        dev->height = 576;
        cx2341x_fill_defaults(&dev->params);
@@ -1106,64 +1170,36 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
                dev->height = 576;
        }
 
-       err = cx8802_init_common(dev);
-       if (0 != err)
-               goto fail_free;
-
        /* blackbird stuff */
        printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
               core->name);
        host_setup(dev->core);
 
-       list_add_tail(&dev->devlist,&cx8802_devlist);
        blackbird_register_video(dev);
 
        /* initial device configuration: needed ? */
 
        return 0;
 
- fail_free:
-       kfree(dev);
  fail_core:
-       cx88_core_put(core,pci_dev);
        return err;
 }
 
-static void __devexit blackbird_remove(struct pci_dev *pci_dev)
+static int cx8802_blackbird_remove(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
-
        /* blackbird */
-       blackbird_unregister_video(dev);
-       list_del(&dev->devlist);
+       blackbird_unregister_video(drv->core->dvbdev);
 
-       /* common */
-       cx8802_fini_common(dev);
-       cx88_core_put(dev->core,dev->pci);
-       kfree(dev);
+       return 0;
 }
 
-static struct pci_device_id cx8802_pci_tbl[] = {
-       {
-               .vendor       = 0x14f1,
-               .device       = 0x8802,
-               .subvendor    = PCI_ANY_ID,
-               .subdevice    = PCI_ANY_ID,
-       },{
-               /* --- end of list --- */
-       }
-};
-MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
-
-static struct pci_driver blackbird_pci_driver = {
-       .name     = "cx88-blackbird",
-       .id_table = cx8802_pci_tbl,
-       .probe    = blackbird_probe,
-       .remove   = __devexit_p(blackbird_remove),
-#ifdef CONFIG_PM
-       .suspend  = cx8802_suspend_common,
-       .resume   = cx8802_resume_common,
-#endif
+static struct cx8802_driver cx8802_blackbird_driver = {
+       .type_id        = CX88_MPEG_BLACKBIRD,
+       .hw_access      = CX8802_DRVCTL_SHARED,
+       .probe          = cx8802_blackbird_probe,
+       .remove         = cx8802_blackbird_remove,
+       .advise_acquire = cx8802_blackbird_advise_acquire,
+       .advise_release = cx8802_blackbird_advise_release,
 };
 
 static int blackbird_init(void)
@@ -1176,17 +1212,22 @@ static int blackbird_init(void)
        printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
               SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-       return pci_register_driver(&blackbird_pci_driver);
+       cx88_ioctl_hook = mpeg_do_ioctl;
+       cx88_ioctl_translator = mpeg_translate_ioctl;
+       return cx8802_register_driver(&cx8802_blackbird_driver);
 }
 
 static void blackbird_fini(void)
 {
-       pci_unregister_driver(&blackbird_pci_driver);
+       cx8802_unregister_driver(&cx8802_blackbird_driver);
 }
 
 module_init(blackbird_init);
 module_exit(blackbird_fini);
 
+EXPORT_SYMBOL(cx88_ioctl_hook);
+EXPORT_SYMBOL(cx88_ioctl_translator);
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
index f764a57c56be53abdca042ad26211cdc80c7ec90..c791708b13362bfb5d7f4b0d31919bc28e196683 100644 (file)
@@ -281,18 +281,22 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000bde2,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x0000bde6,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000bde6,
+                       .extadc = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0000bd62,
+                       .extadc = 1,
                },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -353,6 +357,7 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
+                       .extadc = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
@@ -523,6 +528,7 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
+                       .extadc = 1,
                }},
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -646,18 +652,22 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x00009d80,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00009d76,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x00009d76,
+                       .extadc = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x00009d00,
+                       .extadc = 1,
                },
                .mpeg           = CX88_MPEG_BLACKBIRD,
        },
@@ -786,25 +796,29 @@ struct cx88_board cx88_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-               .mpeg           = CX88_MPEG_BLACKBIRD,
                .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 0,
                        .gpio0  = 0x0000cd73,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 1,
                        .gpio0  = 0x0000cd73,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 3,
                        .gpio0  = 0x0000cdb3,
+                       .extadc = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
                        .vmux   = 2,
                        .gpio0  = 0x0000cdf3,
+                       .extadc = 1,
                },
+               .mpeg           = CX88_MPEG_BLACKBIRD,
        },
        [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
                 /* Alexander Wold <awold@bigfoot.com> */
@@ -1050,7 +1064,6 @@ struct cx88_board cx88_boards[] = {
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
-               /* FIXME: Audio not working for s-video / composite inputs. */
                .name           = "KWorld HardwareMpegTV XPert",
                .tuner_type     = TUNER_PHILIPS_TDA8290,
                .radio_type     = UNSET,
@@ -1065,10 +1078,12 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x3de6,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x3de6,
+                       .extadc = 1,
                }},
                .radio = {
                        .type   = CX88_RADIO,
@@ -1252,35 +1267,35 @@ struct cx88_board cx88_boards[] = {
                        .gpio0  = 0x070b,
                }},
        },
-       [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
-              .name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
-              .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
-              .radio_type     = UNSET,
-              .tuner_addr     = ADDR_UNSET,
-              .radio_addr     = ADDR_UNSET,
-              .input          = {{
-                      .type   = CX88_VMUX_TELEVISION,
-                      .vmux   = 0,
-                      .gpio0  = 0x003fffff,
-                      .gpio1  = 0x00e00000,
-                      .gpio2  = 0x003fffff,
-                      .gpio3  = 0x02000000,
-              },{
-                      .type   = CX88_VMUX_COMPOSITE1,
-                      .vmux   = 1,
-                      .gpio0  = 0x003fffff,
-                      .gpio1  = 0x00e00000,
-                      .gpio2  = 0x003fffff,
-                      .gpio3  = 0x02000000,
-               },{
-                      .type   = CX88_VMUX_SVIDEO,
-                      .vmux   = 2,
-                      .gpio0  = 0x003fffff,
-                      .gpio1  = 0x00e00000,
-                      .gpio2  = 0x003fffff,
-                      .gpio3  = 0x02000000,
-              }},
-       },
+       [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
+               .name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
+               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x003fffff,
+                       .gpio1  = 0x00e00000,
+                       .gpio2  = 0x003fffff,
+                       .gpio3  = 0x02000000,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x003fffff,
+                       .gpio1  = 0x00e00000,
+                       .gpio2  = 0x003fffff,
+                       .gpio3  = 0x02000000,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x003fffff,
+                       .gpio1  = 0x00e00000,
+                       .gpio2  = 0x003fffff,
+                       .gpio3  = 0x02000000,
+               }},
+       },
        [CX88_BOARD_HAUPPAUGE_HVR1300] = {
                .name           = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
                .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
@@ -1293,17 +1308,20 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0xe780,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0xe780,
+                       .extadc = 1,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0xe780,
+                       .extadc = 1,
                }},
                /* fixme: Add radio support */
-               .mpeg           = CX88_MPEG_DVB,
+               .mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
        },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1513,6 +1531,10 @@ struct cx88_subid cx88_subids[] = {
        },{
                .subvendor = 0x17de,
                .subdevice = 0x0840,
+              .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+       },{
+              .subvendor = 0x1421,
+              .subdevice = 0x0305,
                .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
        },{
                .subvendor = 0x18ac,
index 0ef13e7efa2ee2efc6841913338ed48c2f22fe29..8b203354fccdff8f533702fba23610a6a9f0f3c8 100644 (file)
@@ -42,7 +42,7 @@
 #include "cx22702.h"
 #include "or51132.h"
 #include "lgdt330x.h"
-#include "lg_h06xf.h"
+#include "lgh06xf.h"
 #include "nxt200x.h"
 #include "cx24123.h"
 #include "isl6421.h"
@@ -57,7 +57,7 @@ module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
 
 #define dprintk(level,fmt, arg...)     if (debug >= level) \
-       printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg)
+       printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
 
 /* ------------------------------------------------------------------ */
 
@@ -74,8 +74,8 @@ static int dvb_buf_setup(struct videobuf_queue *q,
        return 0;
 }
 
-static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-                          enum v4l2_field field)
+static int dvb_buf_prepare(struct videobuf_queue *q,
+                          struct videobuf_buffer *vb, enum v4l2_field field)
 {
        struct cx8802_dev *dev = q->priv_data;
        return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
@@ -87,7 +87,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
        cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
 }
 
-static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void dvb_buf_release(struct videobuf_queue *q,
+                           struct videobuf_buffer *vb)
 {
        cx88_free_buffer(q, (struct cx88_buffer*)vb);
 }
@@ -100,6 +101,26 @@ static struct videobuf_queue_ops dvb_qops = {
 };
 
 /* ------------------------------------------------------------------ */
+
+static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct cx8802_driver *drv = NULL;
+       int ret = 0;
+
+       drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
+       if (drv) {
+               if (acquire)
+                       ret = drv->request_acquire(drv);
+               else
+                       ret = drv->request_release(drv);
+       }
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
@@ -268,35 +289,6 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
 };
 #endif
 
-static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
-                                        struct dvb_frontend_parameters *params)
-{
-       u8 pllbuf[4];
-       struct cx8802_dev *dev= fe->dvb->priv;
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0,
-                 .buf = pllbuf, .len = 4 };
-       int err;
-
-       dvb_pll_configure(dev->core->pll_desc, pllbuf,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "cx88-dvb: %s error "
-                      "(addr %02x <- %02x, err = %i)\n",
-                      __FUNCTION__, pllbuf[0], pllbuf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
 static struct zl10353_config dvico_fusionhdtv_hybrid = {
        .demod_address = 0x0f,
        .no_tuner      = 1,
@@ -311,28 +303,12 @@ static struct cx22702_config connexant_refboard_config = {
        .output_mode   = CX22702_SERIAL_OUTPUT,
 };
 
-static struct cx22702_config hauppauge_novat_config = {
-       .demod_address = 0x43,
-       .output_mode   = CX22702_SERIAL_OUTPUT,
-};
-
-static struct cx22702_config hauppauge_hvr1100_config = {
+static struct cx22702_config hauppauge_hvr_config = {
        .demod_address = 0x63,
        .output_mode   = CX22702_SERIAL_OUTPUT,
 };
 
-static struct cx22702_config hauppauge_hvr1300_config = {
-       .demod_address = 0x63,
-       .output_mode   = CX22702_SERIAL_OUTPUT,
-};
-
-static struct cx22702_config hauppauge_hvr3000_config = {
-       .demod_address = 0x63,
-       .output_mode = CX22702_SERIAL_OUTPUT,
-};
-
-static int or51132_set_ts_param(struct dvb_frontend* fe,
-                               int is_punctured)
+static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
        dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
@@ -344,50 +320,6 @@ static struct or51132_config pchdtv_hd3000 = {
        .set_ts_params = or51132_set_ts_param,
 };
 
-static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
-                                    struct dvb_frontend_parameters* params)
-{
-       /* FIXME make this routine use the tuner-simple code.
-        * It could probably be shared with a number of ATSC
-        * frontends. Many share the same tuner with analog TV. */
-
-       struct cx8802_dev *dev= fe->dvb->priv;
-       struct cx88_core *core = dev->core;
-       u8 buf[4];
-       struct i2c_msg msg =
-               { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
-       int err;
-
-       dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
-       dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-               __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
-               printk(KERN_WARNING "cx88-dvb: %s error "
-                      "(addr %02x <- %02x, err = %i)\n",
-                      __FUNCTION__, buf[0], buf[1], err);
-               if (err < 0)
-                       return err;
-               else
-                       return -EREMOTEIO;
-       }
-       return 0;
-}
-
-static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
-                                    struct dvb_frontend_parameters* params)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-       struct cx88_core *core = dev->core;
-
-       /* Put the analog decoder in standby to keep it quiet */
-       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
-       return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
-}
-
 static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
@@ -432,8 +364,7 @@ static struct lgdt330x_config pchdtv_hd5500 = {
        .set_ts_params = lgdt330x_set_ts_param,
 };
 
-static int nxt200x_set_ts_param(struct dvb_frontend* fe,
-                               int is_punctured)
+static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
 {
        struct cx8802_dev *dev= fe->dvb->priv;
        dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
@@ -469,11 +400,10 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
        struct cx8802_dev *dev= fe->dvb->priv;
        struct cx88_core *core = dev->core;
 
-       if (voltage == SEC_VOLTAGE_OFF) {
+       if (voltage == SEC_VOLTAGE_OFF)
                cx_write(MO_GP0_IO, 0x000006fb);
-       } else {
+       else
                cx_write(MO_GP0_IO, 0x000006f9);
-       }
 
        if (core->prev_set_voltage)
                return core->prev_set_voltage(fe, voltage);
@@ -522,7 +452,7 @@ static int dvb_register(struct cx8802_dev *dev)
        switch (dev->core->board) {
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
                dev->dvb.frontend = dvb_attach(cx22702_attach,
-                                              &hauppauge_novat_config,
+                                              &connexant_refboard_config,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
@@ -547,32 +477,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
                dev->dvb.frontend = dvb_attach(cx22702_attach,
-                                              &hauppauge_hvr1100_config,
-                                              &dev->core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap,
-                                  &dvb_pll_fmd1216me);
-               }
-               break;
-       case CX88_BOARD_HAUPPAUGE_HVR1300:
-               dev->dvb.frontend = dvb_attach(cx22702_attach,
-                                              &hauppauge_hvr1300_config,
-                                              &dev->core->i2c_adap);
-               if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap,
-                                  &dvb_pll_fmd1216me);
-               }
-               break;
-       case CX88_BOARD_HAUPPAUGE_HVR3000:
-               dev->dvb.frontend = dvb_attach(cx22702_attach,
-                                              &hauppauge_hvr3000_config,
+                                              &hauppauge_hvr_config,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap,
-                                  &dvb_pll_fmd1216me);
+                                  &dev->core->i2c_adap, &dvb_pll_fmd1216me);
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -647,18 +556,17 @@ static int dvb_register(struct cx8802_dev *dev)
 #endif
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_thomson_fe6600;
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_hybrid,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap,
+                                  &dvb_pll_thomson_fe6600);
                }
                break;
        case CX88_BOARD_PCHDTV_HD3000:
-               dev->dvb.frontend = dvb_attach(or51132_attach,
-                                              &pchdtv_hd3000,
+               dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
@@ -679,13 +587,13 @@ static int dvb_register(struct cx8802_dev *dev)
 
                /* Select RF connector callback */
                fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_microtune_4042;
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap,
+                                  &dvb_pll_microtune_4042);
                }
                }
                break;
@@ -699,13 +607,13 @@ static int dvb_register(struct cx8802_dev *dev)
                mdelay(100);
                cx_set(MO_GP0_IO, 9);
                mdelay(200);
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap,
+                                  &dvb_pll_thomson_dtt761x);
                }
                }
                break;
@@ -723,7 +631,8 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &fusionhdtv_5_gold,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+                       dvb_attach(lgh06xf_attach, dev->dvb.frontend,
+                                  &dev->core->i2c_adap);
                }
                }
                break;
@@ -741,7 +650,8 @@ static int dvb_register(struct cx8802_dev *dev)
                                               &pchdtv_hd5500,
                                               &dev->core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+                       dvb_attach(lgh06xf_attach, dev->dvb.frontend,
+                                  &dev->core->i2c_adap);
                }
                }
                break;
@@ -782,6 +692,24 @@ static int dvb_register(struct cx8802_dev *dev)
                        dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
                }
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR1300:
+               dev->dvb.frontend = dvb_attach(cx22702_attach,
+                                              &hauppauge_hvr_config,
+                                              &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+               }
+               break;
+       case CX88_BOARD_HAUPPAUGE_HVR3000:
+               dev->dvb.frontend = dvb_attach(cx22702_attach,
+                                              &hauppauge_hvr_config,
+                                              &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+                                  &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+               }
+               break;
        default:
                printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
                       dev->core->name);
@@ -796,6 +724,8 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
                dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
        }
+       /* Ensure all frontends negotiate bus access */
+       dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
        /* Put the analog decoder in standby to keep it quiet */
        cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
@@ -806,37 +736,67 @@ static int dvb_register(struct cx8802_dev *dev)
 
 /* ----------------------------------------------------------- */
 
-static int __devinit dvb_probe(struct pci_dev *pci_dev,
-                              const struct pci_device_id *pci_id)
+/* CX8802 MPEG -> mini driver - We have been given the hardware */
+static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *dev;
-       struct cx88_core  *core;
+       struct cx88_core *core = drv->core;
+       int err = 0;
+       dprintk( 1, "%s\n", __FUNCTION__);
+
+       switch (core->board) {
+       case CX88_BOARD_HAUPPAUGE_HVR1300:
+               /* We arrive here with either the cx23416 or the cx22702
+                * on the bus. Take the bus from the cx23416 and enable the
+                * cx22702 demod
+                */
+               cx_set(MO_GP0_IO,   0x00000080); /* cx22702 out of reset and enable */
+               cx_clear(MO_GP0_IO, 0x00000004);
+               udelay(1000);
+               break;
+       default:
+               err = -ENODEV;
+       }
+       return err;
+}
+
+/* CX8802 MPEG -> mini driver - We no longer have the hardware */
+static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+       int err = 0;
+       dprintk( 1, "%s\n", __FUNCTION__);
+
+       switch (core->board) {
+       case CX88_BOARD_HAUPPAUGE_HVR1300:
+               /* Do Nothing, leave the cx22702 on the bus. */
+               break;
+       default:
+               err = -ENODEV;
+       }
+       return err;
+}
+
+static int cx8802_dvb_probe(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+       struct cx8802_dev *dev = drv->core->dvbdev;
        int err;
 
-       /* general setup */
-       core = cx88_core_get(pci_dev);
-       if (NULL == core)
-               return -EINVAL;
+       dprintk( 1, "%s\n", __FUNCTION__);
+       dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+               core->board,
+               core->name,
+               core->pci_bus,
+               core->pci_slot);
 
        err = -ENODEV;
        if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
                goto fail_core;
 
-       err = -ENOMEM;
-       dev = kzalloc(sizeof(*dev),GFP_KERNEL);
-       if (NULL == dev)
-               goto fail_core;
-       dev->pci = pci_dev;
-       dev->core = core;
-
-       err = cx8802_init_common(dev);
-       if (0 != err)
-               goto fail_free;
-
 #ifdef HAVE_VP3054_I2C
        err = vp3054_i2c_probe(dev);
        if (0 != err)
-               goto fail_free;
+               goto fail_core;
 #endif
 
        /* dvb stuff */
@@ -848,28 +808,16 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
                            sizeof(struct cx88_buffer),
                            dev);
        err = dvb_register(dev);
-       if (0 != err)
-               goto fail_fini;
+       if (err != 0)
+               printk("%s dvb_register failed err = %d\n", __FUNCTION__, err);
 
-       /* Maintain a reference to cx88-video can query the 8802 device. */
-       core->dvbdev = dev;
-       return 0;
-
- fail_fini:
-       cx8802_fini_common(dev);
- fail_free:
-       kfree(dev);
  fail_core:
-       cx88_core_put(core,pci_dev);
        return err;
 }
 
-static void __devexit dvb_remove(struct pci_dev *pci_dev)
+static int cx8802_dvb_remove(struct cx8802_driver *drv)
 {
-       struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
-
-       /* Destroy any 8802 reference. */
-       dev->core->dvbdev = NULL;
+       struct cx8802_dev *dev = drv->core->dvbdev;
 
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
@@ -878,33 +826,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev)
        vp3054_i2c_remove(dev);
 #endif
 
-       /* common */
-       cx8802_fini_common(dev);
-       cx88_core_put(dev->core,dev->pci);
-       kfree(dev);
+       return 0;
 }
 
-static struct pci_device_id cx8802_pci_tbl[] = {
-       {
-               .vendor       = 0x14f1,
-               .device       = 0x8802,
-               .subvendor    = PCI_ANY_ID,
-               .subdevice    = PCI_ANY_ID,
-       },{
-               /* --- end of list --- */
-       }
-};
-MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
-
-static struct pci_driver dvb_pci_driver = {
-       .name     = "cx88-dvb",
-       .id_table = cx8802_pci_tbl,
-       .probe    = dvb_probe,
-       .remove   = __devexit_p(dvb_remove),
-#ifdef CONFIG_PM
-       .suspend  = cx8802_suspend_common,
-       .resume   = cx8802_resume_common,
-#endif
+static struct cx8802_driver cx8802_dvb_driver = {
+       .type_id        = CX88_MPEG_DVB,
+       .hw_access      = CX8802_DRVCTL_SHARED,
+       .probe          = cx8802_dvb_probe,
+       .remove         = cx8802_dvb_remove,
+       .advise_acquire = cx8802_dvb_advise_acquire,
+       .advise_release = cx8802_dvb_advise_release,
 };
 
 static int dvb_init(void)
@@ -917,12 +848,12 @@ static int dvb_init(void)
        printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
               SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-       return pci_register_driver(&dvb_pci_driver);
+       return cx8802_register_driver(&cx8802_dvb_driver);
 }
 
 static void dvb_fini(void)
 {
-       pci_unregister_driver(&dvb_pci_driver);
+       cx8802_unregister_driver(&cx8802_dvb_driver);
 }
 
 module_init(dvb_init);
index e60a0a52e4b2c6c03612fe90a60bf72c6d0924a3..8136673fe9e8b5d8d3551748dd7bc50c2c020685 100644 (file)
@@ -155,6 +155,35 @@ static void cx88_ir_work(struct work_struct *work)
        mod_timer(&ir->timer, timeout);
 }
 
+static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+{
+       if (ir->polling) {
+               INIT_WORK(&ir->work, cx88_ir_work);
+               init_timer(&ir->timer);
+               ir->timer.function = ir_timer;
+               ir->timer.data = (unsigned long)ir;
+               schedule_work(&ir->work);
+       }
+       if (ir->sampling) {
+               core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
+               cx_write(MO_DDS_IO, 0xa80a80);  /* 4 kHz sample rate */
+               cx_write(MO_DDSCFG_IO, 0x5);    /* enable */
+       }
+}
+
+static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+{
+       if (ir->sampling) {
+               cx_write(MO_DDSCFG_IO, 0x0);
+               core->pci_irqmask &= ~(1 << 18);
+       }
+
+       if (ir->polling) {
+               del_timer_sync(&ir->timer);
+               flush_scheduled_work();
+       }
+}
+
 /* ---------------------------------------------------------------------- */
 
 int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
@@ -163,14 +192,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        struct input_dev *input_dev;
        IR_KEYTAB_TYPE *ir_codes = NULL;
        int ir_type = IR_TYPE_OTHER;
+       int err = -ENOMEM;
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!ir || !input_dev) {
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENOMEM;
-       }
+       if (!ir || !input_dev)
+               goto err_out_free;
 
        ir->input = input_dev;
 
@@ -280,9 +307,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        }
 
        if (NULL == ir_codes) {
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENODEV;
+               err = -ENODEV;
+               goto err_out_free;
        }
 
        /* init input device */
@@ -307,23 +333,22 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        ir->core = core;
        core->ir = ir;
 
-       if (ir->polling) {
-               INIT_WORK(&ir->work, cx88_ir_work);
-               init_timer(&ir->timer);
-               ir->timer.function = ir_timer;
-               ir->timer.data = (unsigned long)ir;
-               schedule_work(&ir->work);
-       }
-       if (ir->sampling) {
-               core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
-               cx_write(MO_DDS_IO, 0xa80a80);  /* 4 kHz sample rate */
-               cx_write(MO_DDSCFG_IO, 0x5);    /* enable */
-       }
+       cx88_ir_start(core, ir);
 
        /* all done */
-       input_register_device(ir->input);
+       err = input_register_device(ir->input);
+       if (err)
+               goto err_out_stop;
 
        return 0;
+
+ err_out_stop:
+       cx88_ir_stop(core, ir);
+       core->ir = NULL;
+ err_out_free:
+       input_free_device(input_dev);
+       kfree(ir);
+       return err;
 }
 
 int cx88_ir_fini(struct cx88_core *core)
@@ -334,15 +359,7 @@ int cx88_ir_fini(struct cx88_core *core)
        if (NULL == ir)
                return 0;
 
-       if (ir->sampling) {
-               cx_write(MO_DDSCFG_IO, 0x0);
-               core->pci_irqmask &= ~(1 << 18);
-       }
-       if (ir->polling) {
-               del_timer(&ir->timer);
-               flush_scheduled_work();
-       }
-
+       cx88_ir_stop(core, ir);
        input_unregister_device(ir->input);
        kfree(ir);
 
index 6b23a4e6f66d2447f50d389b8b046298e447ba29..1fe1a833c7c714a5672537d1ee5d90bd4dcad2f1 100644 (file)
@@ -44,8 +44,12 @@ module_param(debug,int,0644);
 MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
 
 #define dprintk(level,fmt, arg...)     if (debug >= level) \
-       printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg)
+       printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg)
 
+#define mpeg_dbg(level,fmt, arg...)    if (debug >= level) \
+       printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg)
+
+static LIST_HEAD(cx8802_devlist);
 /* ------------------------------------------------------------------ */
 
 static int cx8802_start_dma(struct cx8802_dev    *dev,
@@ -65,17 +69,13 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 
        /* FIXME: this needs a review.
         * also: move to cx88-blackbird + cx88-dvb source files? */
-       if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) {
-               /* Report a warning until the mini driver patch is applied,
-                * else the following conditions will set the dma registers incorrectly.
-                * This will be removed in the next major patch and changes to the conditions
-                * will be made.
-                */
-               printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__);
-               return -EINVAL;
-       }
 
-       if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) {
+       dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
+
+       if ( (core->active_type_id == CX88_MPEG_DVB) &&
+               (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
+
+               dprintk( 1, "cx8802_start_dma doing .dvb\n");
                /* negedge driven & software reset */
                cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
                udelay(100);
@@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
                        cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
                        udelay(100);
                        break;
+               case CX88_BOARD_HAUPPAUGE_HVR1300:
+                       break;
                default:
                        cx_write(TS_SOP_STAT, 0x00);
                        break;
                }
                cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
                udelay(100);
-       }
-
-       if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+       } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
+               (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
+               dprintk( 1, "cx8802_start_dma doing .blackbird\n");
                cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
 
                cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
@@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 
                cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
                udelay(100);
+       } else {
+               printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
+                       cx88_boards[core->board].mpeg );
+               return -EINVAL;
        }
 
        /* reset counter */
@@ -542,8 +548,315 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
        return 0;
 }
 
+struct cx8802_dev * cx8802_get_device(struct inode *inode)
+{
+       int minor = iminor(inode);
+       struct cx8802_dev *h = NULL;
+       struct list_head *list;
+
+       list_for_each(list,&cx8802_devlist) {
+               h = list_entry(list, struct cx8802_dev, devlist);
+               if (h->mpeg_dev->minor == minor)
+                       return h;
+       }
+
+       return NULL;
+}
+
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
+{
+       struct cx8802_dev *h = NULL;
+       struct cx8802_driver *d = NULL;
+       struct list_head *list;
+       struct list_head *list2;
+
+       list_for_each(list,&cx8802_devlist) {
+               h = list_entry(list, struct cx8802_dev, devlist);
+               if (h != dev)
+                       continue;
+
+               list_for_each(list2, &h->drvlist.devlist) {
+                       d = list_entry(list2, struct cx8802_driver, devlist);
+
+                       /* only unregister the correct driver type */
+                       if (d->type_id == btype) {
+                               return d;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+/* Driver asked for hardware access. */
+int cx8802_request_acquire(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+
+       /* Fail a request for hardware if the device is busy. */
+       if (core->active_type_id != CX88_BOARD_NONE)
+               return -EBUSY;
+
+       if (drv->advise_acquire)
+       {
+               core->active_type_id = drv->type_id;
+               drv->advise_acquire(drv);
+
+               mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+       }
+
+       return 0;
+}
+
+/* Driver asked to release hardware. */
+int cx8802_request_release(struct cx8802_driver *drv)
+{
+       struct cx88_core *core = drv->core;
+
+       if (drv->advise_release)
+       {
+               drv->advise_release(drv);
+               core->active_type_id = CX88_BOARD_NONE;
+               mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+       }
+
+       return 0;
+}
+
+static int cx8802_check_driver(struct cx8802_driver *drv)
+{
+       if (drv == NULL)
+               return -ENODEV;
+
+       if ((drv->type_id != CX88_MPEG_DVB) &&
+               (drv->type_id != CX88_MPEG_BLACKBIRD))
+               return -EINVAL;
+
+       if ((drv->hw_access != CX8802_DRVCTL_SHARED) &&
+               (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE))
+               return -EINVAL;
+
+       if ((drv->probe == NULL) ||
+               (drv->remove == NULL) ||
+               (drv->advise_acquire == NULL) ||
+               (drv->advise_release == NULL))
+               return -EINVAL;
+
+       return 0;
+}
+
+int cx8802_register_driver(struct cx8802_driver *drv)
+{
+       struct cx8802_dev *h;
+       struct cx8802_driver *driver;
+       struct list_head *list;
+       int err = 0, i = 0;
+
+       printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
+               drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+               drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+
+       if ((err = cx8802_check_driver(drv)) != 0) {
+               printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
+               return err;
+       }
+
+       list_for_each(list,&cx8802_devlist) {
+               h = list_entry(list, struct cx8802_dev, devlist);
+
+               printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
+                       h->core->name,h->pci->subsystem_vendor,
+                       h->pci->subsystem_device,cx88_boards[h->core->board].name,
+                       h->core->board);
+
+               /* Bring up a new struct for each driver instance */
+               driver = kzalloc(sizeof(*drv),GFP_KERNEL);
+               if (driver == NULL)
+                       return -ENOMEM;
+
+               /* Snapshot of the driver registration data */
+               drv->core = h->core;
+               drv->suspend = cx8802_suspend_common;
+               drv->resume = cx8802_resume_common;
+               drv->request_acquire = cx8802_request_acquire;
+               drv->request_release = cx8802_request_release;
+               memcpy(driver, drv, sizeof(*driver));
+
+               err = drv->probe(driver);
+               if (err == 0) {
+                       i++;
+                       mutex_lock(&drv->core->lock);
+                       list_add_tail(&driver->devlist,&h->drvlist.devlist);
+                       mutex_unlock(&drv->core->lock);
+               } else {
+                       printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
+               }
+
+       }
+       if (i == 0)
+               err = -ENODEV;
+       else
+               err = 0;
+
+       return err;
+}
+
+int cx8802_unregister_driver(struct cx8802_driver *drv)
+{
+       struct cx8802_dev *h;
+       struct cx8802_driver *d;
+       struct list_head *list;
+       struct list_head *list2, *q;
+       int err = 0, i = 0;
+
+       printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
+               drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
+
+       list_for_each(list,&cx8802_devlist) {
+               i++;
+               h = list_entry(list, struct cx8802_dev, devlist);
+
+               printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
+                       h->core->name,h->pci->subsystem_vendor,
+                       h->pci->subsystem_device,cx88_boards[h->core->board].name,
+                       h->core->board);
+
+               list_for_each_safe(list2, q, &h->drvlist.devlist) {
+                       d = list_entry(list2, struct cx8802_driver, devlist);
+
+                       /* only unregister the correct driver type */
+                       if (d->type_id != drv->type_id)
+                               continue;
+
+                       err = d->remove(d);
+                       if (err == 0) {
+                               mutex_lock(&drv->core->lock);
+                               list_del(list2);
+                               mutex_unlock(&drv->core->lock);
+                       } else
+                               printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
+
+               }
+
+       }
+
+       return err;
+}
+
 /* ----------------------------------------------------------- */
+static int __devinit cx8802_probe(struct pci_dev *pci_dev,
+                              const struct pci_device_id *pci_id)
+{
+       struct cx8802_dev *dev;
+       struct cx88_core  *core;
+       int err;
+
+       /* general setup */
+       core = cx88_core_get(pci_dev);
+       if (NULL == core)
+               return -EINVAL;
 
+       printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
+
+       err = -ENODEV;
+       if (!cx88_boards[core->board].mpeg)
+               goto fail_core;
+
+       err = -ENOMEM;
+       dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+       if (NULL == dev)
+               goto fail_core;
+       dev->pci = pci_dev;
+       dev->core = core;
+
+       err = cx8802_init_common(dev);
+       if (err != 0)
+               goto fail_free;
+
+       INIT_LIST_HEAD(&dev->drvlist.devlist);
+       list_add_tail(&dev->devlist,&cx8802_devlist);
+
+       /* Maintain a reference so cx88-video can query the 8802 device. */
+       core->dvbdev = dev;
+       return 0;
+
+ fail_free:
+       kfree(dev);
+ fail_core:
+       cx88_core_put(core,pci_dev);
+       return err;
+}
+
+static void __devexit cx8802_remove(struct pci_dev *pci_dev)
+{
+       struct cx8802_dev *dev;
+       struct cx8802_driver *h;
+       struct list_head *list;
+
+       dev = pci_get_drvdata(pci_dev);
+
+       dprintk( 1, "%s\n", __FUNCTION__);
+
+       list_for_each(list,&dev->drvlist.devlist) {
+               h = list_entry(list, struct cx8802_driver, devlist);
+               dprintk( 1, " ->driver\n");
+               if (h->remove == NULL) {
+                       printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__);
+                       continue;
+               }
+               printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id);
+               cx8802_unregister_driver(h);
+               list_del(&dev->drvlist.devlist);
+       }
+
+       /* Destroy any 8802 reference. */
+       dev->core->dvbdev = NULL;
+
+       /* common */
+       cx8802_fini_common(dev);
+       cx88_core_put(dev->core,dev->pci);
+       kfree(dev);
+}
+
+static struct pci_device_id cx8802_pci_tbl[] = {
+       {
+               .vendor       = 0x14f1,
+               .device       = 0x8802,
+               .subvendor    = PCI_ANY_ID,
+               .subdevice    = PCI_ANY_ID,
+       },{
+               /* --- end of list --- */
+       }
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver cx8802_pci_driver = {
+       .name     = "cx88-mpeg driver manager",
+       .id_table = cx8802_pci_tbl,
+       .probe    = cx8802_probe,
+       .remove   = __devexit_p(cx8802_remove),
+};
+
+static int cx8802_init(void)
+{
+       printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
+              (CX88_VERSION_CODE >> 16) & 0xff,
+              (CX88_VERSION_CODE >>  8) & 0xff,
+              CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+       return pci_register_driver(&cx8802_pci_driver);
+}
+
+static void cx8802_fini(void)
+{
+       pci_unregister_driver(&cx8802_pci_driver);
+}
+
+module_init(cx8802_init);
+module_exit(cx8802_fini);
 EXPORT_SYMBOL(cx8802_buf_prepare);
 EXPORT_SYMBOL(cx8802_buf_queue);
 EXPORT_SYMBOL(cx8802_cancel_buffers);
@@ -551,9 +864,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers);
 EXPORT_SYMBOL(cx8802_init_common);
 EXPORT_SYMBOL(cx8802_fini_common);
 
-EXPORT_SYMBOL(cx8802_suspend_common);
-EXPORT_SYMBOL(cx8802_resume_common);
-
+EXPORT_SYMBOL(cx8802_register_driver);
+EXPORT_SYMBOL(cx8802_unregister_driver);
+EXPORT_SYMBOL(cx8802_get_device);
+EXPORT_SYMBOL(cx8802_get_driver);
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
index 58ba9f773524605833a7bdc0b6267ba149b0d025..3482e0114d43ec4cba7bbedf643824a26c9bcd20 100644 (file)
@@ -143,19 +143,6 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
        cx88_start_audio_dma(core);
 
        if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
-               /* sets sound input from external adc */
-               switch (core->board) {
-               case CX88_BOARD_HAUPPAUGE_ROSLYN:
-               case CX88_BOARD_KWORLD_MCE200_DELUXE:
-               case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
-               case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
-               case CX88_BOARD_ASUS_PVR_416:
-                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
-                       break;
-               default:
-                       cx_set(AUD_CTL, EN_I2SIN_ENABLE);
-               }
-
                cx_write(AUD_I2SINPUTCNTL, 4);
                cx_write(AUD_BAUDRATE, 1);
                /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
index 90e298d074d11f688f825bb9986426569546586a..8613378428fdd45899ed30ef81334e69de78808a 100644 (file)
@@ -454,6 +454,14 @@ static int video_mux(struct cx88_core *core, unsigned int input)
                cx_clear(MO_FILTER_ODD,   0x00002020);
                break;
        }
+
+       if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+               /* sets sound input from external adc */
+               if (INPUT(input)->extadc)
+                       cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+               else
+                       cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+       }
        return 0;
 }
 
@@ -1490,6 +1498,30 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                mutex_unlock(&core->lock);
                return 0;
        }
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       /* ioctls to allow direct acces to the cx2388x registers */
+       case VIDIOC_INT_G_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != 0)
+                       return -EINVAL;
+               /* cx2388x has a 24-bit register space */
+               reg->val = cx_read(reg->reg&0xffffff);
+               return 0;
+       }
+       case VIDIOC_INT_S_REGISTER:
+       {
+               struct v4l2_register *reg = arg;
+
+               if (reg->i2c_id != 0)
+                       return -EINVAL;
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               cx_write(reg->reg&0xffffff, reg->val);
+               return 0;
+       }
+#endif
 
        default:
                return v4l_compat_translate_ioctl(inode,file,cmd,arg,
index 3bc91aad4fe5df80b4d3d9bcea67ce3807b71462..7054e941f1d7ceb76759a8adf26e42e368ede4ca 100644 (file)
@@ -74,6 +74,11 @@ enum cx88_board_type {
        CX88_MPEG_BLACKBIRD
 };
 
+enum cx8802_board_access {
+       CX8802_DRVCTL_SHARED    = 1,
+       CX8802_DRVCTL_EXCLUSIVE = 2,
+};
+
 /* ----------------------------------------------------------- */
 /* tv norms                                                    */
 
@@ -220,6 +225,7 @@ struct cx88_input {
        enum cx88_itype type;
        unsigned int    vmux;
        u32             gpio0, gpio1, gpio2, gpio3;
+       unsigned int    extadc:1;
 };
 
 struct cx88_board {
@@ -330,6 +336,7 @@ struct cx88_core {
 
        /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
        struct cx8802_dev          *dvbdev;
+       enum cx88_board_type       active_type_id;
 };
 
 struct cx8800_dev;
@@ -405,6 +412,31 @@ struct cx8802_suspend_state {
        int                        disabled;
 };
 
+struct cx8802_driver {
+       struct cx88_core *core;
+       struct list_head devlist;
+
+       /* Type of driver and access required */
+       enum cx88_board_type type_id;
+       enum cx8802_board_access hw_access;
+
+       /* MPEG 8802 internal only */
+       int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
+       int (*resume)(struct pci_dev *pci_dev);
+
+       /* MPEG 8802 -> mini driver - Driver probe and configuration */
+       int (*probe)(struct cx8802_driver *drv);
+       int (*remove)(struct cx8802_driver *drv);
+
+       /* MPEG 8802 -> mini driver - Access for hardware control */
+       int (*advise_acquire)(struct cx8802_driver *drv);
+       int (*advise_release)(struct cx8802_driver *drv);
+
+       /* MPEG 8802 <- mini driver - Access for hardware control */
+       int (*request_acquire)(struct cx8802_driver *drv);
+       int (*request_release)(struct cx8802_driver *drv);
+};
+
 struct cx8802_dev {
        struct cx88_core           *core;
        spinlock_t                 slock;
@@ -439,6 +471,9 @@ struct cx8802_dev {
 
        /* mpeg params */
        struct cx2341x_mpeg_params params;
+
+       /* List of attached drivers */
+       struct cx8802_driver       drvlist;
 };
 
 /* ----------------------------------------------------------- */
@@ -571,6 +606,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
 int cx88_audio_thread(void *data);
 
+int cx8802_register_driver(struct cx8802_driver *drv);
+int cx8802_unregister_driver(struct cx8802_driver *drv);
+struct cx8802_dev * cx8802_get_device(struct inode *inode);
+struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
+
 /* ----------------------------------------------------------- */
 /* cx88-input.c                                                */
 
@@ -600,6 +640,13 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 extern const u32 cx88_user_ctrls[];
 extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
 
+/* ----------------------------------------------------------- */
+/* cx88-blackbird.c                                            */
+/* used by cx88-ivtv ioctl emulation layer                     */
+extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg);
+extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+
 /*
  * Local variables:
  * c-basic-offset: 8
index ab87e7bfe84f1c6afc3ab91de80a2be12f211ea3..59edf58204de311935cc3d807b7d2bd3745c148d 100644 (file)
@@ -305,15 +305,14 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        int ir_type;
        struct IR_i2c *ir;
        struct input_dev *input_dev;
+       int err;
 
        ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!ir || !input_dev) {
-               input_free_device(input_dev);
-               kfree(ir);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_out_free;
        }
-       memset(ir,0,sizeof(*ir));
 
        ir->c = client_template;
        ir->input = input_dev;
@@ -355,32 +354,34 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                break;
        case 0x7a:
        case 0x47:
+       case 0x71:
                /* Handled by saa7134-input */
                name        = "SAA713x remote";
                ir_type     = IR_TYPE_OTHER;
                break;
        default:
                /* shouldn't happen */
-               printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr);
-               kfree(ir);
-               return -1;
+               printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+               err = -ENODEV;
+               goto err_out_free;
        }
 
        /* Sets name */
        snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
-       ir->ir_codes=ir_codes;
+       ir->ir_codes = ir_codes;
 
        /* register i2c device
         * At device register, IR codes may be changed to be
         * board dependent.
         */
-       i2c_attach_client(&ir->c);
+       err = i2c_attach_client(&ir->c);
+       if (err)
+               goto err_out_free;
 
        /* If IR not supported or disabled, unregisters driver */
        if (ir->get_key == NULL) {
-               i2c_detach_client(&ir->c);
-               kfree(ir);
-               return -1;
+               err = -ENODEV;
+               goto err_out_detach;
        }
 
        /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
@@ -389,15 +390,17 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                 ir->c.dev.bus_id);
 
        /* init + register input device */
-       ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes);
+       ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
        input_dev->id.bustype = BUS_I2C;
        input_dev->name       = ir->c.name;
        input_dev->phys       = ir->phys;
 
-       /* register event device */
-       input_register_device(ir->input);
+       err = input_register_device(ir->input);
+       if (err)
+               goto err_out_detach;
+
        printk(DEVNAME ": %s detected at %s [%s]\n",
-              ir->input->name,ir->input->phys,adap->name);
+              ir->input->name, ir->input->phys, adap->name);
 
        /* start polling via eventd */
        INIT_WORK(&ir->work, ir_work);
@@ -407,6 +410,13 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        schedule_work(&ir->work);
 
        return 0;
+
+ err_out_detach:
+       i2c_detach_client(&ir->c);
+ err_out_free:
+       input_free_device(input_dev);
+       kfree(ir);
+       return err;
 }
 
 static int ir_detach(struct i2c_client *client)
@@ -414,7 +424,7 @@ static int ir_detach(struct i2c_client *client)
        struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
-       del_timer(&ir->timer);
+       del_timer_sync(&ir->timer);
        flush_scheduled_work();
 
        /* unregister devices */
@@ -439,7 +449,7 @@ static int ir_probe(struct i2c_adapter *adap)
        */
 
        static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
        static const int probe_em28XX[] = { 0x30, 0x47, -1 };
        const int *probe = NULL;
        struct i2c_client c;
index b0aea4002d1124235922f2396553e43f0079092b..152cc6b3e1521232a510442a8e6b980585c6ec75 100644 (file)
@@ -160,10 +160,6 @@ static int mxb_probe(struct saa7146_dev* dev)
                printk("mxb: saa7111 i2c module not available.\n");
                return -ENODEV;
        }
-       if ((result = request_module("tuner")) < 0) {
-               printk("mxb: tuner i2c module not available.\n");
-               return -ENODEV;
-       }
        if ((result = request_module("tea6420")) < 0) {
                printk("mxb: tea6420 i2c module not available.\n");
                return -ENODEV;
@@ -176,6 +172,10 @@ static int mxb_probe(struct saa7146_dev* dev)
                printk("mxb: tda9840 i2c module not available.\n");
                return -ENODEV;
        }
+       if ((result = request_module("tuner")) < 0) {
+               printk("mxb: tuner i2c module not available.\n");
+               return -ENODEV;
+       }
 
        mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
        if( NULL == mxb ) {
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
new file mode 100644 (file)
index 0000000..89dd18c
--- /dev/null
@@ -0,0 +1,1333 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
+ * by Jonathan Corbet with substantial inspiration from Mark
+ * McClelland's ovcamchip code.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/i2c.h>
+
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net.");
+MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
+MODULE_LICENSE("GPL");
+
+/*
+ * Basic window sizes.  These probably belong somewhere more globally
+ * useful.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
+#define QVGA_WIDTH     320
+#define QVGA_HEIGHT    240
+#define CIF_WIDTH      352
+#define CIF_HEIGHT     288
+#define QCIF_WIDTH     176
+#define        QCIF_HEIGHT     144
+
+/*
+ * Our nominal (default) frame rate.
+ */
+#define OV7670_FRAME_RATE 30
+
+/*
+ * The 7670 sits on i2c with ID 0x42
+ */
+#define OV7670_I2C_ADDR 0x42
+
+/* Registers */
+#define REG_GAIN       0x00    /* Gain lower 8 bits (rest in vref) */
+#define REG_BLUE       0x01    /* blue gain */
+#define REG_RED                0x02    /* red gain */
+#define REG_VREF       0x03    /* Pieces of GAIN, VSTART, VSTOP */
+#define REG_COM1       0x04    /* Control 1 */
+#define  COM1_CCIR656    0x40  /* CCIR656 enable */
+#define REG_BAVE       0x05    /* U/B Average level */
+#define REG_GbAVE      0x06    /* Y/Gb Average level */
+#define REG_AECHH      0x07    /* AEC MS 5 bits */
+#define REG_RAVE       0x08    /* V/R Average level */
+#define REG_COM2       0x09    /* Control 2 */
+#define  COM2_SSLEEP     0x10  /* Soft sleep mode */
+#define REG_PID                0x0a    /* Product ID MSB */
+#define REG_VER                0x0b    /* Product ID LSB */
+#define REG_COM3       0x0c    /* Control 3 */
+#define  COM3_SWAP       0x40    /* Byte swap */
+#define  COM3_SCALEEN    0x08    /* Enable scaling */
+#define  COM3_DCWEN      0x04    /* Enable downsamp/crop/window */
+#define REG_COM4       0x0d    /* Control 4 */
+#define REG_COM5       0x0e    /* All "reserved" */
+#define REG_COM6       0x0f    /* Control 6 */
+#define REG_AECH       0x10    /* More bits of AEC value */
+#define REG_CLKRC      0x11    /* Clocl control */
+#define   CLK_EXT        0x40    /* Use external clock directly */
+#define   CLK_SCALE      0x3f    /* Mask for internal clock scale */
+#define REG_COM7       0x12    /* Control 7 */
+#define   COM7_RESET     0x80    /* Register reset */
+#define   COM7_FMT_MASK          0x38
+#define   COM7_FMT_VGA   0x00
+#define          COM7_FMT_CIF    0x20    /* CIF format */
+#define   COM7_FMT_QVGA          0x10    /* QVGA format */
+#define   COM7_FMT_QCIF          0x08    /* QCIF format */
+#define          COM7_RGB        0x04    /* bits 0 and 2 - RGB format */
+#define          COM7_YUV        0x00    /* YUV */
+#define          COM7_BAYER      0x01    /* Bayer format */
+#define          COM7_PBAYER     0x05    /* "Processed bayer" */
+#define REG_COM8       0x13    /* Control 8 */
+#define   COM8_FASTAEC   0x80    /* Enable fast AGC/AEC */
+#define   COM8_AECSTEP   0x40    /* Unlimited AEC step size */
+#define   COM8_BFILT     0x20    /* Band filter enable */
+#define   COM8_AGC       0x04    /* Auto gain enable */
+#define   COM8_AWB       0x02    /* White balance enable */
+#define   COM8_AEC       0x01    /* Auto exposure enable */
+#define REG_COM9       0x14    /* Control 9  - gain ceiling */
+#define REG_COM10      0x15    /* Control 10 */
+#define   COM10_HSYNC    0x40    /* HSYNC instead of HREF */
+#define   COM10_PCLK_HB          0x20    /* Suppress PCLK on horiz blank */
+#define   COM10_HREF_REV  0x08   /* Reverse HREF */
+#define   COM10_VS_LEAD          0x04    /* VSYNC on clock leading edge */
+#define   COM10_VS_NEG   0x02    /* VSYNC negative */
+#define   COM10_HS_NEG   0x01    /* HSYNC negative */
+#define REG_HSTART     0x17    /* Horiz start high bits */
+#define REG_HSTOP      0x18    /* Horiz stop high bits */
+#define REG_VSTART     0x19    /* Vert start high bits */
+#define REG_VSTOP      0x1a    /* Vert stop high bits */
+#define REG_PSHFT      0x1b    /* Pixel delay after HREF */
+#define REG_MIDH       0x1c    /* Manuf. ID high */
+#define REG_MIDL       0x1d    /* Manuf. ID low */
+#define REG_MVFP       0x1e    /* Mirror / vflip */
+#define   MVFP_MIRROR    0x20    /* Mirror image */
+#define   MVFP_FLIP      0x10    /* Vertical flip */
+
+#define REG_AEW                0x24    /* AGC upper limit */
+#define REG_AEB                0x25    /* AGC lower limit */
+#define REG_VPT                0x26    /* AGC/AEC fast mode op region */
+#define REG_HSYST      0x30    /* HSYNC rising edge delay */
+#define REG_HSYEN      0x31    /* HSYNC falling edge delay */
+#define REG_HREF       0x32    /* HREF pieces */
+#define REG_TSLB       0x3a    /* lots of stuff */
+#define   TSLB_YLAST     0x04    /* UYVY or VYUY - see com13 */
+#define REG_COM11      0x3b    /* Control 11 */
+#define   COM11_NIGHT    0x80    /* NIght mode enable */
+#define   COM11_NMFR     0x60    /* Two bit NM frame rate */
+#define   COM11_HZAUTO   0x10    /* Auto detect 50/60 Hz */
+#define          COM11_50HZ      0x08    /* Manual 50Hz select */
+#define   COM11_EXP      0x02
+#define REG_COM12      0x3c    /* Control 12 */
+#define   COM12_HREF     0x80    /* HREF always */
+#define REG_COM13      0x3d    /* Control 13 */
+#define   COM13_GAMMA    0x80    /* Gamma enable */
+#define          COM13_UVSAT     0x40    /* UV saturation auto adjustment */
+#define   COM13_UVSWAP   0x01    /* V before U - w/TSLB */
+#define REG_COM14      0x3e    /* Control 14 */
+#define   COM14_DCWEN    0x10    /* DCW/PCLK-scale enable */
+#define REG_EDGE       0x3f    /* Edge enhancement factor */
+#define REG_COM15      0x40    /* Control 15 */
+#define   COM15_R10F0    0x00    /* Data range 10 to F0 */
+#define          COM15_R01FE     0x80    /*            01 to FE */
+#define   COM15_R00FF    0xc0    /*            00 to FF */
+#define   COM15_RGB565   0x10    /* RGB565 output */
+#define   COM15_RGB555   0x30    /* RGB555 output */
+#define REG_COM16      0x41    /* Control 16 */
+#define   COM16_AWBGAIN   0x08   /* AWB gain enable */
+#define REG_COM17      0x42    /* Control 17 */
+#define   COM17_AECWIN   0xc0    /* AEC window - must match COM4 */
+#define   COM17_CBAR     0x08    /* DSP Color bar */
+
+/*
+ * This matrix defines how the colors are generated, must be
+ * tweaked to adjust hue and saturation.
+ *
+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
+ *
+ * They are nine-bit signed quantities, with the sign bit
+ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
+ */
+#define        REG_CMATRIX_BASE 0x4f
+#define   CMATRIX_LEN 6
+#define REG_CMATRIX_SIGN 0x58
+
+
+#define REG_BRIGHT     0x55    /* Brightness */
+#define REG_CONTRAS    0x56    /* Contrast control */
+
+#define REG_GFIX       0x69    /* Fix gain control */
+
+#define REG_RGB444     0x8c    /* RGB 444 control */
+#define   R444_ENABLE    0x02    /* Turn on RGB444, overrides 5x5 */
+#define   R444_RGBX      0x01    /* Empty nibble at end */
+
+#define REG_HAECC1     0x9f    /* Hist AEC/AGC control 1 */
+#define REG_HAECC2     0xa0    /* Hist AEC/AGC control 2 */
+
+#define REG_BD50MAX    0xa5    /* 50hz banding step limit */
+#define REG_HAECC3     0xa6    /* Hist AEC/AGC control 3 */
+#define REG_HAECC4     0xa7    /* Hist AEC/AGC control 4 */
+#define REG_HAECC5     0xa8    /* Hist AEC/AGC control 5 */
+#define REG_HAECC6     0xa9    /* Hist AEC/AGC control 6 */
+#define REG_HAECC7     0xaa    /* Hist AEC/AGC control 7 */
+#define REG_BD60MAX    0xab    /* 60hz banding step limit */
+
+
+/*
+ * Information we maintain about a known sensor.
+ */
+struct ov7670_format_struct;  /* coming later */
+struct ov7670_info {
+       struct ov7670_format_struct *fmt;  /* Current format */
+       unsigned char sat;              /* Saturation value */
+       int hue;                        /* Hue value */
+};
+
+
+
+
+/*
+ * The default register settings, as obtained from OmniVision.  There
+ * is really no making sense of most of these - lots of "reserved" values
+ * and such.
+ *
+ * These settings give VGA YUYV.
+ */
+
+struct regval_list {
+       unsigned char reg_num;
+       unsigned char value;
+};
+
+static struct regval_list ov7670_default_regs[] = {
+       { REG_COM7, COM7_RESET },
+/*
+ * Clock scale: 3 = 15fps
+ *              2 = 20fps
+ *              1 = 30fps
+ */
+       { REG_CLKRC, 0x1 },     /* OV: clock scale (30 fps) */
+       { REG_TSLB,  0x04 },    /* OV */
+       { REG_COM7, 0 },        /* VGA */
+       /*
+        * Set the hardware window.  These values from OV don't entirely
+        * make sense - hstop is less than hstart.  But they work...
+        */
+       { REG_HSTART, 0x13 },   { REG_HSTOP, 0x01 },
+       { REG_HREF, 0xb6 },     { REG_VSTART, 0x02 },
+       { REG_VSTOP, 0x7a },    { REG_VREF, 0x0a },
+
+       { REG_COM3, 0 },        { REG_COM14, 0 },
+       /* Mystery scaling numbers */
+       { 0x70, 0x3a },         { 0x71, 0x35 },
+       { 0x72, 0x11 },         { 0x73, 0xf0 },
+       { 0xa2, 0x02 },         { REG_COM10, 0x0 },
+
+       /* Gamma curve values */
+       { 0x7a, 0x20 },         { 0x7b, 0x10 },
+       { 0x7c, 0x1e },         { 0x7d, 0x35 },
+       { 0x7e, 0x5a },         { 0x7f, 0x69 },
+       { 0x80, 0x76 },         { 0x81, 0x80 },
+       { 0x82, 0x88 },         { 0x83, 0x8f },
+       { 0x84, 0x96 },         { 0x85, 0xa3 },
+       { 0x86, 0xaf },         { 0x87, 0xc4 },
+       { 0x88, 0xd7 },         { 0x89, 0xe8 },
+
+       /* AGC and AEC parameters.  Note we start by disabling those features,
+          then turn them only after tweaking the values. */
+       { REG_COM8, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT },
+       { REG_GAIN, 0 },        { REG_AECH, 0 },
+       { REG_COM4, 0x40 }, /* magic reserved bit */
+       { REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+       { REG_BD50MAX, 0x05 },  { REG_BD60MAX, 0x07 },
+       { REG_AEW, 0x95 },      { REG_AEB, 0x33 },
+       { REG_VPT, 0xe3 },      { REG_HAECC1, 0x78 },
+       { REG_HAECC2, 0x68 },   { 0xa1, 0x03 }, /* magic */
+       { REG_HAECC3, 0xd8 },   { REG_HAECC4, 0xd8 },
+       { REG_HAECC5, 0xf0 },   { REG_HAECC6, 0x90 },
+       { REG_HAECC7, 0x94 },
+       { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC },
+
+       /* Almost all of these are magic "reserved" values.  */
+       { REG_COM5, 0x61 },     { REG_COM6, 0x4b },
+       { 0x16, 0x02 },         { REG_MVFP, 0x07|MVFP_MIRROR },
+       { 0x21, 0x02 },         { 0x22, 0x91 },
+       { 0x29, 0x07 },         { 0x33, 0x0b },
+       { 0x35, 0x0b },         { 0x37, 0x1d },
+       { 0x38, 0x71 },         { 0x39, 0x2a },
+       { REG_COM12, 0x78 },    { 0x4d, 0x40 },
+       { 0x4e, 0x20 },         { REG_GFIX, 0 },
+       { 0x6b, 0x4a },         { 0x74, 0x10 },
+       { 0x8d, 0x4f },         { 0x8e, 0 },
+       { 0x8f, 0 },            { 0x90, 0 },
+       { 0x91, 0 },            { 0x96, 0 },
+       { 0x9a, 0 },            { 0xb0, 0x84 },
+       { 0xb1, 0x0c },         { 0xb2, 0x0e },
+       { 0xb3, 0x82 },         { 0xb8, 0x0a },
+
+       /* More reserved magic, some of which tweaks white balance */
+       { 0x43, 0x0a },         { 0x44, 0xf0 },
+       { 0x45, 0x34 },         { 0x46, 0x58 },
+       { 0x47, 0x28 },         { 0x48, 0x3a },
+       { 0x59, 0x88 },         { 0x5a, 0x88 },
+       { 0x5b, 0x44 },         { 0x5c, 0x67 },
+       { 0x5d, 0x49 },         { 0x5e, 0x0e },
+       { 0x6c, 0x0a },         { 0x6d, 0x55 },
+       { 0x6e, 0x11 },         { 0x6f, 0x9f }, /* "9e for advance AWB" */
+       { 0x6a, 0x40 },         { REG_BLUE, 0x40 },
+       { REG_RED, 0x60 },
+       { REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC|COM8_AWB },
+
+       /* Matrix coefficients */
+       { 0x4f, 0x80 },         { 0x50, 0x80 },
+       { 0x51, 0 },            { 0x52, 0x22 },
+       { 0x53, 0x5e },         { 0x54, 0x80 },
+       { 0x58, 0x9e },
+
+       { REG_COM16, COM16_AWBGAIN },   { REG_EDGE, 0 },
+       { 0x75, 0x05 },         { 0x76, 0xe1 },
+       { 0x4c, 0 },            { 0x77, 0x01 },
+       { REG_COM13, 0xc3 },    { 0x4b, 0x09 },
+       { 0xc9, 0x60 },         { REG_COM16, 0x38 },
+       { 0x56, 0x40 },
+
+       { 0x34, 0x11 },         { REG_COM11, COM11_EXP|COM11_HZAUTO },
+       { 0xa4, 0x88 },         { 0x96, 0 },
+       { 0x97, 0x30 },         { 0x98, 0x20 },
+       { 0x99, 0x30 },         { 0x9a, 0x84 },
+       { 0x9b, 0x29 },         { 0x9c, 0x03 },
+       { 0x9d, 0x4c },         { 0x9e, 0x3f },
+       { 0x78, 0x04 },
+
+       /* Extra-weird stuff.  Some sort of multiplexor register */
+       { 0x79, 0x01 },         { 0xc8, 0xf0 },
+       { 0x79, 0x0f },         { 0xc8, 0x00 },
+       { 0x79, 0x10 },         { 0xc8, 0x7e },
+       { 0x79, 0x0a },         { 0xc8, 0x80 },
+       { 0x79, 0x0b },         { 0xc8, 0x01 },
+       { 0x79, 0x0c },         { 0xc8, 0x0f },
+       { 0x79, 0x0d },         { 0xc8, 0x20 },
+       { 0x79, 0x09 },         { 0xc8, 0x80 },
+       { 0x79, 0x02 },         { 0xc8, 0xc0 },
+       { 0x79, 0x03 },         { 0xc8, 0x40 },
+       { 0x79, 0x05 },         { 0xc8, 0x30 },
+       { 0x79, 0x26 },
+
+       { 0xff, 0xff }, /* END MARKER */
+};
+
+
+/*
+ * Here we'll try to encapsulate the changes for just the output
+ * video format.
+ *
+ * RGB656 and YUV422 come from OV; RGB444 is homebrewed.
+ *
+ * IMPORTANT RULE: the first entry must be for COM7, see ov7670_s_fmt for why.
+ */
+
+
+static struct regval_list ov7670_fmt_yuv422[] = {
+       { REG_COM7, 0x0 },  /* Selects YUV mode */
+       { REG_RGB444, 0 },      /* No RGB444 please */
+       { REG_COM1, 0 },
+       { REG_COM15, COM15_R00FF },
+       { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
+       { 0x4f, 0x80 },         /* "matrix coefficient 1" */
+       { 0x50, 0x80 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x22 },         /* "matrix coefficient 4" */
+       { 0x53, 0x5e },         /* "matrix coefficient 5" */
+       { 0x54, 0x80 },         /* "matrix coefficient 6" */
+       { REG_COM13, COM13_GAMMA|COM13_UVSAT },
+       { 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb565[] = {
+       { REG_COM7, COM7_RGB }, /* Selects RGB mode */
+       { REG_RGB444, 0 },      /* No RGB444 please */
+       { REG_COM1, 0x0 },
+       { REG_COM15, COM15_RGB565 },
+       { REG_COM9, 0x38 },     /* 16x gain ceiling; 0x8 is reserved bit */
+       { 0x4f, 0xb3 },         /* "matrix coefficient 1" */
+       { 0x50, 0xb3 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x3d },         /* "matrix coefficient 4" */
+       { 0x53, 0xa7 },         /* "matrix coefficient 5" */
+       { 0x54, 0xe4 },         /* "matrix coefficient 6" */
+       { REG_COM13, COM13_GAMMA|COM13_UVSAT },
+       { 0xff, 0xff },
+};
+
+static struct regval_list ov7670_fmt_rgb444[] = {
+       { REG_COM7, COM7_RGB }, /* Selects RGB mode */
+       { REG_RGB444, R444_ENABLE },    /* Enable xxxxrrrr ggggbbbb */
+       { REG_COM1, 0x40 },     /* Magic reserved bit */
+       { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */
+       { REG_COM9, 0x38 },     /* 16x gain ceiling; 0x8 is reserved bit */
+       { 0x4f, 0xb3 },         /* "matrix coefficient 1" */
+       { 0x50, 0xb3 },         /* "matrix coefficient 2" */
+       { 0x51, 0    },         /* vb */
+       { 0x52, 0x3d },         /* "matrix coefficient 4" */
+       { 0x53, 0xa7 },         /* "matrix coefficient 5" */
+       { 0x54, 0xe4 },         /* "matrix coefficient 6" */
+       { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 },  /* Magic rsvd bit */
+       { 0xff, 0xff },
+};
+
+
+
+
+/*
+ * Low-level register I/O.
+ */
+
+static int ov7670_read(struct i2c_client *c, unsigned char reg,
+               unsigned char *value)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(c, reg);
+       if (ret >= 0)
+               *value = (unsigned char) ret;
+       return ret;
+}
+
+
+static int ov7670_write(struct i2c_client *c, unsigned char reg,
+               unsigned char value)
+{
+       return i2c_smbus_write_byte_data(c, reg, value);
+}
+
+
+/*
+ * Write a list of register settings; ff/ff stops the process.
+ */
+static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
+{
+       while (vals->reg_num != 0xff || vals->value != 0xff) {
+               int ret = ov7670_write(c, vals->reg_num, vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       return 0;
+}
+
+
+/*
+ * Stuff that knows about the sensor.
+ */
+static void ov7670_reset(struct i2c_client *client)
+{
+       ov7670_write(client, REG_COM7, COM7_RESET);
+       msleep(1);
+}
+
+
+static int ov7670_init(struct i2c_client *client)
+{
+       return ov7670_write_array(client, ov7670_default_regs);
+}
+
+
+
+static int ov7670_detect(struct i2c_client *client)
+{
+       unsigned char v;
+       int ret;
+
+       ret = ov7670_init(client);
+       if (ret < 0)
+               return ret;
+       ret = ov7670_read(client, REG_MIDH, &v);
+       if (ret < 0)
+               return ret;
+       if (v != 0x7f) /* OV manuf. id. */
+               return -ENODEV;
+       ret = ov7670_read(client, REG_MIDL, &v);
+       if (ret < 0)
+               return ret;
+       if (v != 0xa2)
+               return -ENODEV;
+       /*
+        * OK, we know we have an OmniVision chip...but which one?
+        */
+       ret = ov7670_read(client, REG_PID, &v);
+       if (ret < 0)
+               return ret;
+       if (v != 0x76)  /* PID + VER = 0x76 / 0x73 */
+               return -ENODEV;
+       ret = ov7670_read(client, REG_VER, &v);
+       if (ret < 0)
+               return ret;
+       if (v != 0x73)  /* PID + VER = 0x76 / 0x73 */
+               return -ENODEV;
+       return 0;
+}
+
+
+/*
+ * Store information about the video data format.  The color matrix
+ * is deeply tied into the format, so keep the relevant values here.
+ * The magic matrix nubmers come from OmniVision.
+ */
+static struct ov7670_format_struct {
+       __u8 *desc;
+       __u32 pixelformat;
+       struct regval_list *regs;
+       int cmatrix[CMATRIX_LEN];
+} ov7670_formats[] = {
+       {
+               .desc           = "YUYV 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .regs           = ov7670_fmt_yuv422,
+               .cmatrix        = { 128, -128, 0, -34, -94, 128 },
+       },
+       {
+               .desc           = "RGB 444",
+               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .regs           = ov7670_fmt_rgb444,
+               .cmatrix        = { 179, -179, 0, -61, -176, 228 },
+       },
+       {
+               .desc           = "RGB 565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .regs           = ov7670_fmt_rgb565,
+               .cmatrix        = { 179, -179, 0, -61, -176, 228 },
+       },
+};
+#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0]))
+
+/*
+ * All formats we support are 2 bytes/pixel.
+ */
+#define BYTES_PER_PIXEL 2
+
+/*
+ * Then there is the issue of window sizes.  Try to capture the info here.
+ */
+
+/*
+ * QCIF mode is done (by OV) in a very strange way - it actually looks like
+ * VGA with weird scaling options - they do *not* use the canned QCIF mode
+ * which is allegedly provided by the sensor.  So here's the weird register
+ * settings.
+ */
+static struct regval_list ov7670_qcif_regs[] = {
+       { REG_COM3, COM3_SCALEEN|COM3_DCWEN },
+       { REG_COM3, COM3_DCWEN },
+       { REG_COM14, COM14_DCWEN | 0x01},
+       { 0x73, 0xf1 },
+       { 0xa2, 0x52 },
+       { 0x7b, 0x1c },
+       { 0x7c, 0x28 },
+       { 0x7d, 0x3c },
+       { 0x7f, 0x69 },
+       { REG_COM9, 0x38 },
+       { 0xa1, 0x0b },
+       { 0x74, 0x19 },
+       { 0x9a, 0x80 },
+       { 0x43, 0x14 },
+       { REG_COM13, 0xc0 },
+       { 0xff, 0xff },
+};
+
+static struct ov7670_win_size {
+       int     width;
+       int     height;
+       unsigned char com7_bit;
+       int     hstart;         /* Start/stop values for the camera.  Note */
+       int     hstop;          /* that they do not always make complete */
+       int     vstart;         /* sense to humans, but evidently the sensor */
+       int     vstop;          /* will do the right thing... */
+       struct regval_list *regs; /* Regs to tweak */
+/* h/vref stuff */
+} ov7670_win_sizes[] = {
+       /* VGA */
+       {
+               .width          = VGA_WIDTH,
+               .height         = VGA_HEIGHT,
+               .com7_bit       = COM7_FMT_VGA,
+               .hstart         = 158,          /* These values from */
+               .hstop          =  14,          /* Omnivision */
+               .vstart         =  10,
+               .vstop          = 490,
+               .regs           = NULL,
+       },
+       /* CIF */
+       {
+               .width          = CIF_WIDTH,
+               .height         = CIF_HEIGHT,
+               .com7_bit       = COM7_FMT_CIF,
+               .hstart         = 170,          /* Empirically determined */
+               .hstop          =  90,
+               .vstart         =  14,
+               .vstop          = 494,
+               .regs           = NULL,
+       },
+       /* QVGA */
+       {
+               .width          = QVGA_WIDTH,
+               .height         = QVGA_HEIGHT,
+               .com7_bit       = COM7_FMT_QVGA,
+               .hstart         = 164,          /* Empirically determined */
+               .hstop          =  20,
+               .vstart         =  14,
+               .vstop          = 494,
+               .regs           = NULL,
+       },
+       /* QCIF */
+       {
+               .width          = QCIF_WIDTH,
+               .height         = QCIF_HEIGHT,
+               .com7_bit       = COM7_FMT_VGA, /* see comment above */
+               .hstart         = 456,          /* Empirically determined */
+               .hstop          =  24,
+               .vstart         =  14,
+               .vstop          = 494,
+               .regs           = ov7670_qcif_regs,
+       },
+};
+
+#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+
+
+/*
+ * Store a set of start/stop values into the camera.
+ */
+static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
+               int vstart, int vstop)
+{
+       int ret;
+       unsigned char v;
+/*
+ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
+ * 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);
+       v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+       msleep(10);
+       ret += ov7670_write(client, 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);
+       v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
+       msleep(10);
+       ret += ov7670_write(client, REG_VREF, v);
+       return ret;
+}
+
+
+static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
+{
+       struct ov7670_format_struct *ofmt;
+
+       if (fmt->index >= N_OV7670_FMTS)
+               return -EINVAL;
+
+       ofmt = ov7670_formats + fmt->index;
+       fmt->flags = 0;
+       strcpy(fmt->description, ofmt->desc);
+       fmt->pixelformat = ofmt->pixelformat;
+       return 0;
+}
+
+
+static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
+               struct ov7670_format_struct **ret_fmt,
+               struct ov7670_win_size **ret_wsize)
+{
+       int index;
+       struct ov7670_win_size *wsize;
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+       for (index = 0; index < N_OV7670_FMTS; index++)
+               if (ov7670_formats[index].pixelformat == pix->pixelformat)
+                       break;
+       if (index >= N_OV7670_FMTS)
+               return -EINVAL;
+       if (ret_fmt != NULL)
+               *ret_fmt = ov7670_formats + index;
+       /*
+        * Fields: the OV devices claim to be progressive.
+        */
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = V4L2_FIELD_NONE;
+       else if (pix->field != V4L2_FIELD_NONE)
+               return -EINVAL;
+       /*
+        * Round requested image size down to the nearest
+        * we support, but not below the smallest.
+        */
+       for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
+            wsize++)
+               if (pix->width >= wsize->width && pix->height >= wsize->height)
+                       break;
+       if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
+               wsize--;   /* Take the smallest one */
+       if (ret_wsize != NULL)
+               *ret_wsize = wsize;
+       /*
+        * Note the size we'll actually handle.
+        */
+       pix->width = wsize->width;
+       pix->height = wsize->height;
+       pix->bytesperline = pix->width*BYTES_PER_PIXEL;
+       pix->sizeimage = pix->height*pix->bytesperline;
+       return 0;
+}
+
+/*
+ * Set a format.
+ */
+static int ov7670_s_fmt(struct i2c_client *c, 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;
+
+       ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
+       if (ret)
+               return ret;
+       /*
+        * COM7 is a pain in the ass, it doesn't like to be read then
+        * quickly written afterward.  But we have everything we need
+        * to set it absolutely here, as long as the format-specific
+        * register sets list it first.
+        */
+       com7 = ovfmt->regs[0].value;
+       com7 |= wsize->com7_bit;
+       ov7670_write(c, 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,
+                       wsize->vstop);
+       ret = 0;
+       if (wsize->regs)
+               ret = ov7670_write_array(c, wsize->regs);
+       info->fmt = ovfmt;
+       return 0;
+}
+
+/*
+ * 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)
+{
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       unsigned char clkrc;
+       int ret;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       if (ret < 0)
+               return ret;
+       memset(cp, 0, sizeof(struct v4l2_captureparm));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = 1;
+       cp->timeperframe.denominator = OV7670_FRAME_RATE;
+       if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)
+               cp->timeperframe.denominator /= (clkrc & CLK_SCALE);
+       return 0;
+}
+
+static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       unsigned char clkrc;
+       int ret, div;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (cp->extendedmode != 0)
+               return -EINVAL;
+       /*
+        * CLKRC has a reserved bit, so let's preserve it.
+        */
+       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       if (ret < 0)
+               return ret;
+       if (tpf->numerator == 0 || tpf->denominator == 0)
+               div = 1;  /* Reset to full rate */
+       else
+               div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+       if (div == 0)
+               div = 1;
+       else if (div > CLK_SCALE)
+               div = CLK_SCALE;
+       clkrc = (clkrc & 0x80) | div;
+       tpf->numerator = 1;
+       tpf->denominator = OV7670_FRAME_RATE/div;
+       return ov7670_write(c, REG_CLKRC, clkrc);
+}
+
+
+
+/*
+ * Code for dealing with controls.
+ */
+
+
+
+
+
+static int ov7670_store_cmatrix(struct i2c_client *client,
+               int matrix[CMATRIX_LEN])
+{
+       int i, ret;
+       unsigned char signbits;
+
+       /*
+        * 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);
+       signbits &= 0xc0;
+
+       for (i = 0; i < CMATRIX_LEN; i++) {
+               unsigned char raw;
+
+               if (matrix[i] < 0) {
+                       signbits |= (1 << i);
+                       if (matrix[i] < -255)
+                               raw = 0xff;
+                       else
+                               raw = (-1 * matrix[i]) & 0xff;
+               }
+               else {
+                       if (matrix[i] > 255)
+                               raw = 0xff;
+                       else
+                               raw = matrix[i] & 0xff;
+               }
+               ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
+       }
+       ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
+       return ret;
+}
+
+
+/*
+ * Hue also requires messing with the color matrix.  It also requires
+ * trig functions, which tend not to be well supported in the kernel.
+ * So here is a simple table of sine values, 0-90 degrees, in steps
+ * of five degrees.  Values are multiplied by 1000.
+ *
+ * The following naive approximate trig functions require an argument
+ * carefully limited to -180 <= theta <= 180.
+ */
+#define SIN_STEP 5
+static const int ov7670_sin_table[] = {
+          0,    87,   173,   258,   342,   422,
+        499,   573,   642,   707,   766,   819,
+        866,   906,   939,   965,   984,   996,
+       1000
+};
+
+static int ov7670_sine(int theta)
+{
+       int chs = 1;
+       int sine;
+
+       if (theta < 0) {
+               theta = -theta;
+               chs = -1;
+       }
+       if (theta <= 90)
+               sine = ov7670_sin_table[theta/SIN_STEP];
+       else {
+               theta -= 90;
+               sine = 1000 - ov7670_sin_table[theta/SIN_STEP];
+       }
+       return sine*chs;
+}
+
+static int ov7670_cosine(int theta)
+{
+       theta = 90 - theta;
+       if (theta > 180)
+               theta -= 360;
+       else if (theta < -180)
+               theta += 360;
+       return ov7670_sine(theta);
+}
+
+
+
+
+static void ov7670_calc_cmatrix(struct ov7670_info *info,
+               int matrix[CMATRIX_LEN])
+{
+       int i;
+       /*
+        * Apply the current saturation setting first.
+        */
+       for (i = 0; i < CMATRIX_LEN; i++)
+               matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
+       /*
+        * Then, if need be, rotate the hue value.
+        */
+       if (info->hue != 0) {
+               int sinth, costh, tmpmatrix[CMATRIX_LEN];
+
+               memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
+               sinth = ov7670_sine(info->hue);
+               costh = ov7670_cosine(info->hue);
+
+               matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
+               matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
+               matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000;
+               matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000;
+               matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000;
+               matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000;
+       }
+}
+
+
+
+static int ov7670_t_sat(struct i2c_client *client, int value)
+{
+       struct ov7670_info *info = i2c_get_clientdata(client);
+       int matrix[CMATRIX_LEN];
+       int ret;
+
+       info->sat = value;
+       ov7670_calc_cmatrix(info, matrix);
+       ret = ov7670_store_cmatrix(client, matrix);
+       return ret;
+}
+
+static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
+{
+       struct ov7670_info *info = i2c_get_clientdata(client);
+
+       *value = info->sat;
+       return 0;
+}
+
+static int ov7670_t_hue(struct i2c_client *client, int value)
+{
+       struct ov7670_info *info = i2c_get_clientdata(client);
+       int matrix[CMATRIX_LEN];
+       int ret;
+
+       if (value < -180 || value > 180)
+               return -EINVAL;
+       info->hue = value;
+       ov7670_calc_cmatrix(info, matrix);
+       ret = ov7670_store_cmatrix(client, matrix);
+       return ret;
+}
+
+
+static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
+{
+       struct ov7670_info *info = i2c_get_clientdata(client);
+
+       *value = info->hue;
+       return 0;
+}
+
+
+/*
+ * Some weird registers seem to store values in a sign/magnitude format!
+ */
+static unsigned char ov7670_sm_to_abs(unsigned char v)
+{
+       if ((v & 0x80) == 0)
+               return v + 128;
+       else
+               return 128 - (v & 0x7f);
+}
+
+
+static unsigned char ov7670_abs_to_sm(unsigned char v)
+{
+       if (v > 127)
+               return v & 0x7f;
+       else
+               return (128 - v) | 0x80;
+}
+
+static int ov7670_t_brightness(struct i2c_client *client, int value)
+{
+       unsigned char com8, v;
+       int ret;
+
+       ov7670_read(client, REG_COM8, &com8);
+       com8 &= ~COM8_AEC;
+       ov7670_write(client, REG_COM8, com8);
+       v = ov7670_abs_to_sm(value);
+       ret = ov7670_write(client, REG_BRIGHT, v);
+       return ret;
+}
+
+static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
+{
+       unsigned char v;
+       int ret = ov7670_read(client, REG_BRIGHT, &v);
+
+       *value = ov7670_sm_to_abs(v);
+       return ret;
+}
+
+static int ov7670_t_contrast(struct i2c_client *client, int value)
+{
+       return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
+}
+
+static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
+{
+       unsigned char v;
+       int ret = ov7670_read(client, REG_CONTRAS, &v);
+
+       *value = v;
+       return ret;
+}
+
+static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
+{
+       int ret;
+       unsigned char v;
+
+       ret = ov7670_read(client, REG_MVFP, &v);
+       *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
+       return ret;
+}
+
+
+static int ov7670_t_hflip(struct i2c_client *client, int value)
+{
+       unsigned char v;
+       int ret;
+
+       ret = ov7670_read(client, REG_MVFP, &v);
+       if (value)
+               v |= MVFP_MIRROR;
+       else
+               v &= ~MVFP_MIRROR;
+       msleep(10);  /* FIXME */
+       ret += ov7670_write(client, REG_MVFP, v);
+       return ret;
+}
+
+
+
+static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
+{
+       int ret;
+       unsigned char v;
+
+       ret = ov7670_read(client, REG_MVFP, &v);
+       *value = (v & MVFP_FLIP) == MVFP_FLIP;
+       return ret;
+}
+
+
+static int ov7670_t_vflip(struct i2c_client *client, int value)
+{
+       unsigned char v;
+       int ret;
+
+       ret = ov7670_read(client, REG_MVFP, &v);
+       if (value)
+               v |= MVFP_FLIP;
+       else
+               v &= ~MVFP_FLIP;
+       msleep(10);  /* FIXME */
+       ret += ov7670_write(client, 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[] =
+{
+       {
+               .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 (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+
+static struct ov7670_control *ov7670_find_control(__u32 id)
+{
+       int i;
+
+       for (i = 0; i < N_CONTROLS; i++)
+               if (ov7670_controls[i].qc.id == id)
+                       return ov7670_controls + i;
+       return NULL;
+}
+
+
+static int ov7670_queryctrl(struct i2c_client *client,
+               struct v4l2_queryctrl *qc)
+{
+       struct ov7670_control *ctrl = ov7670_find_control(qc->id);
+
+       if (ctrl == NULL)
+               return -EINVAL;
+       *qc = ctrl->qc;
+       return 0;
+}
+
+static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+       struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+       int ret;
+
+       if (octrl == NULL)
+               return -EINVAL;
+       ret = octrl->query(client, &ctrl->value);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+       struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+       int ret;
+
+       if (octrl == NULL)
+               return -EINVAL;
+       ret =  octrl->tweak(client, ctrl->value);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+
+
+
+
+
+/*
+ * Basic i2c stuff.
+ */
+static struct i2c_driver ov7670_driver;
+
+static int ov7670_attach(struct i2c_adapter *adapter)
+{
+       int ret;
+       struct i2c_client *client;
+       struct ov7670_info *info;
+
+       /*
+        * 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)
+               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;
+       }
+       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;
+       i2c_attach_client(client);
+       return 0;
+
+  out_free_info:
+       kfree(info);
+  out_free:
+       kfree(client);
+       return ret;
+}
+
+
+static int ov7670_detach(struct i2c_client *client)
+{
+       i2c_detach_client(client);
+       kfree(i2c_get_clientdata(client));
+       kfree(client);
+       return 0;
+}
+
+
+static int ov7670_command(struct i2c_client *client, unsigned int cmd,
+               void *arg)
+{
+       switch (cmd) {
+       case VIDIOC_INT_G_CHIP_IDENT:
+               * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670;
+               return 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;
+}
+
+
+
+static struct i2c_driver ov7670_driver = {
+       .driver = {
+               .name = "ov7670",
+       },
+       .id             = I2C_DRIVERID_OV7670,
+       .class          = I2C_CLASS_CAM_DIGITAL,
+       .attach_adapter = ov7670_attach,
+       .detach_client  = ov7670_detach,
+       .command        = ov7670_command,
+};
+
+
+/*
+ * 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);
index c80c26be6e4d31dd048964525184d676cc96bf0d..848fb233d80861efe8cb88d07787d61aaeb587b2 100644 (file)
@@ -260,6 +260,22 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
                                  sizeof(decoder_ops[0]))) - 1;
        hdw->decoder_ctrl = &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;
index 1f787333d18c03153cb840c9d6307960f3a0c5b2..d2004965187bf54e47455a067881abf27f444950 100644 (file)
@@ -356,28 +356,6 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
        return 0;
 }
 
-static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp)
-{
-       /* If we're dealing with a 24xxx device, force the horizontal
-          maximum to be 720 no matter what, since we can't get the device
-          to work properly with any other value.  Otherwise just return
-          the normal value. */
-       *vp = cptr->info->def.type_int.max_value;
-       if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
-       return 0;
-}
-
-static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp)
-{
-       /* If we're dealing with a 24xxx device, force the horizontal
-          minimum to be 720 no matter what, since we can't get the device
-          to work properly with any other value.  Otherwise just return
-          the normal value. */
-       *vp = cptr->info->def.type_int.min_value;
-       if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
-       return 0;
-}
-
 static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 {
        /* Actual maximum depends on the video standard in effect. */
@@ -758,10 +736,6 @@ static const struct pvr2_ctl_info control_defs[] = {
                .default_value = 720,
                DEFREF(res_hor),
                DEFINT(19,720),
-               /* Hook in check for clamp on horizontal resolution in
-                  order to avoid unsolved problem involving cx25840. */
-               .get_max_value = ctrl_hres_max_get,
-               .get_min_value = ctrl_hres_min_get,
        },{
                .desc = "Vertical capture resolution",
                .name = "resolution_ver",
index 3b9012f8e380671a8595b9bf9847bcc6f2c58242..f9bb41d8f4f3375896fe3580ad8ac815a6c3b172 100644 (file)
@@ -185,6 +185,79 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
        }
 }
 
+
+/* This is a special entry point for cases of I2C transaction attempts to
+   the IR receiver.  The implementation here simulates the IR receiver by
+   issuing a command to the FX2 firmware and using that response to return
+   what the real I2C receiver would have returned.  We use this for 24xxx
+   devices, where the IR receiver chip has been removed and replaced with
+   FX2 related logic. */
+static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
+                       u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+       u8 dat[4];
+       unsigned int stat;
+
+       if (!(rlen || wlen)) {
+               /* This is a probe attempt.  Just let it succeed. */
+               return 0;
+       }
+
+       /* We don't understand this kind of transaction */
+       if ((wlen != 0) || (rlen == 0)) return -EIO;
+
+       if (rlen < 3) {
+               /* Mike Isely <isely@pobox.com> Appears to be a probe
+                  attempt from lirc.  Just fill in zeroes and return.  If
+                  we try instead to do the full transaction here, then bad
+                  things seem to happen within the lirc driver module
+                  (version 0.8.0-7 sources from Debian, when run under
+                  vanilla 2.6.17.6 kernel) - and I don't have the patience
+                  to chase it down. */
+               if (rlen > 0) rdata[0] = 0;
+               if (rlen > 1) rdata[1] = 0;
+               return 0;
+       }
+
+       /* Issue a command to the FX2 to read the IR receiver. */
+       LOCK_TAKE(hdw->ctl_lock); do {
+               hdw->cmd_buffer[0] = 0xec;
+               stat = pvr2_send_request(hdw,
+                                        hdw->cmd_buffer,1,
+                                        hdw->cmd_buffer,4);
+               dat[0] = hdw->cmd_buffer[0];
+               dat[1] = hdw->cmd_buffer[1];
+               dat[2] = hdw->cmd_buffer[2];
+               dat[3] = hdw->cmd_buffer[3];
+       } while (0); LOCK_GIVE(hdw->ctl_lock);
+
+       /* Give up if that operation failed. */
+       if (stat != 0) return stat;
+
+       /* Mangle the results into something that looks like the real IR
+          receiver. */
+       rdata[2] = 0xc1;
+       if (dat[0] != 1) {
+               /* No code received. */
+               rdata[0] = 0;
+               rdata[1] = 0;
+       } else {
+               u16 val;
+               /* Mash the FX2 firmware-provided IR code into something
+                  that the normal i2c chip-level driver expects. */
+               val = dat[1];
+               val <<= 8;
+               val |= dat[2];
+               val >>= 1;
+               val &= ~0x0003;
+               val |= 0x8000;
+               rdata[0] = (val >> 8) & 0xffu;
+               rdata[1] = val & 0xffu;
+       }
+
+       return 0;
+}
+
 /* This is a special entry point that is entered if an I2C operation is
    attempted to a wm8775 chip on model 24xxx hardware.  Autodetect of this
    part doesn't work, but we know it is really there.  So let's look for
@@ -887,17 +960,17 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 {
        unsigned int idx;
 
-       // The default action for all possible I2C addresses is just to do
-       // the transfer normally.
+       /* The default action for all possible I2C addresses is just to do
+          the transfer normally. */
        for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
                hdw->i2c_func[idx] = pvr2_i2c_basic_op;
        }
 
-       // If however we're dealing with new hardware, insert some hacks in
-       // the I2C transfer stack to let things work better.
+       /* However, deal with various special cases for 24xxx hardware. */
        if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
                hdw->i2c_func[0x1b] = i2c_hack_wm8775;
                hdw->i2c_func[0x44] = i2c_hack_cx25840;
+               hdw->i2c_func[0x18] = i2c_24xxx_ir;
        }
 
        // Configure the adapter and set up everything else related to it.
index f28398dd9d935d794d4c23582f9a43294f112517..c2374ed7ba9fe31c35b37197bfd6b4a234911446 100644 (file)
@@ -851,7 +851,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
 
        /* On 60Hz, it is using a higher Vertical Output Size */
        if (!is_50hz)
-               res+=(VRES_60HZ-480)>>1;
+               res += (VRES_60HZ - 480) >> 1;
 
                /* height */
        saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
@@ -907,7 +907,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
 
        /* Activates task "B" */
        saa711x_write(client, R_80_GLOBAL_CNTL_1,
-                               saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20);
+                               saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
 
        return 0;
 }
@@ -932,11 +932,11 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
        if (std & V4L2_STD_525_60) {
                v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
                saa711x_writeregs(client, saa7115_cfg_60hz_video);
-               saa711x_set_size(client,720,480);
+               saa711x_set_size(client, 720, 480);
        } else {
                v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
                saa711x_writeregs(client, saa7115_cfg_50hz_video);
-               saa711x_set_size(client,720,576);
+               saa711x_set_size(client, 720, 576);
        }
 
        /* Register 0E - Bits D6-D4 on NO-AUTO mode
@@ -1464,13 +1464,13 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
        client->driver = &i2c_driver_saa711x;
        snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
-       for (i=0;i<0x0f;i++) {
+       for (i = 0; i < 0x0f; i++) {
                saa711x_write(client, 0, i);
-               name[i] = (saa711x_read(client, 0) &0x0f) +'0';
-               if (name[i]>'9')
-                       name[i]+='a'-'9'-1;
+               name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
+               if (name[i] > '9')
+                       name[i] += 'a' - '9' - 1;
        }
-       name[i]='\0';
+       name[i] = '\0';
 
        saa711x_write(client, 0, 5);
        chip_id = saa711x_read(client, 0) & 0x0f;
index 4abf5c03a740f14c035d771349bd3ea82159772f..ffb0f647a86d6b7b84f873d826a370e19924f75a 100644 (file)
@@ -1,10 +1,6 @@
 /*
  *   SAA713x ALSA support for V4L
  *
- *
- *   Caveats:
- *        - Volume doesn't work (it's always at max)
- *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  *   the Free Software Foundation, version 2
@@ -614,13 +610,18 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
        snd_card_saa7134_pcm_t *pcm;
        snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
        struct saa7134_dev *dev = saa7134->dev;
-       int err;
+       int amux, err;
 
        mutex_lock(&dev->dmasound.lock);
 
        dev->dmasound.read_count  = 0;
        dev->dmasound.read_offset = 0;
 
+       amux = dev->input->amux;
+       if ((amux < 1) || (amux > 3))
+               amux = 1;
+       dev->dmasound.input  =  amux - 1;
+
        mutex_unlock(&dev->dmasound.lock);
 
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
@@ -713,6 +714,8 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
                                  struct snd_ctl_elem_value * ucontrol)
 {
        snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       struct saa7134_dev *dev = chip->dev;
+
        int change, addr = kcontrol->private_value;
        int left, right;
 
@@ -727,10 +730,52 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
        if (right > 20)
                right = 20;
        spin_lock_irq(&chip->mixer_lock);
-       change = chip->mixer_volume[addr][0] != left ||
-                chip->mixer_volume[addr][1] != right;
-       chip->mixer_volume[addr][0] = left;
-       chip->mixer_volume[addr][1] = right;
+       change = 0;
+       if (chip->mixer_volume[addr][0] != left) {
+               change = 1;
+               right = left;
+       }
+       if (chip->mixer_volume[addr][1] != right) {
+               change = 1;
+               left = right;
+       }
+       if (change) {
+               switch (dev->pci->device) {
+                       case PCI_DEVICE_ID_PHILIPS_SAA7134:
+                               switch (addr) {
+                                       case MIXER_ADDR_TVTUNER:
+                                               left = 20;
+                                               break;
+                                       case MIXER_ADDR_LINE1:
+                                               saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
+                                                          (left > 10) ? 0x00 : 0x10);
+                                               break;
+                                       case MIXER_ADDR_LINE2:
+                                               saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
+                                                          (left > 10) ? 0x00 : 0x20);
+                                               break;
+                               }
+                               break;
+                       case PCI_DEVICE_ID_PHILIPS_SAA7133:
+                       case PCI_DEVICE_ID_PHILIPS_SAA7135:
+                               switch (addr) {
+                                       case MIXER_ADDR_TVTUNER:
+                                               left = 20;
+                                               break;
+                                       case MIXER_ADDR_LINE1:
+                                               saa_andorb(0x0594,  0x10,
+                                                          (left > 10) ? 0x00 : 0x10);
+                                               break;
+                                       case MIXER_ADDR_LINE2:
+                                               saa_andorb(0x0594,  0x20,
+                                                          (left > 10) ? 0x00 : 0x20);
+                                               break;
+                               }
+                               break;
+               }
+               chip->mixer_volume[addr][0] = left;
+               chip->mixer_volume[addr][1] = right;
+       }
        spin_unlock_irq(&chip->mixer_lock);
        return change;
 }
index 51f0cfdcb6800aeb13c84df95d25f543672ba5ba..4dead84aff4629d56f29c40cc29311730a807e02 100644 (file)
@@ -2462,14 +2462,17 @@ struct saa7134_board saa7134_boards[] = {
                        .vmux = 1,
                        .amux = TV,
                        .tv   = 1,
+                       .gpio = 0x0000000,
                },{
                        .name = name_comp1,
                        .vmux = 3,
                        .amux = LINE2,
+                       .gpio = 0x0200000,
                },{
                        .name = name_svideo,
                        .vmux = 8,
                        .amux = LINE2,
+                       .gpio = 0x0200000,
                }},
                .radio = {
                        .name = name_radio,
@@ -3022,6 +3025,158 @@ struct saa7134_board saa7134_boards[] = {
                        .amux   = LINE1,
                },
        },
+       [SAA7134_BOARD_PINNACLE_PCTV_310i] = {
+               .name           = "Pinnacle PCTV 310i",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .gpiomask       = 0x000200000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 4,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE2,
+               },{
+                       .name = name_comp2,
+                       .vmux = 0,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux   = TV,
+                       .gpio   = 0x0200000,
+               },
+       },
+       [SAA7134_BOARD_AVERMEDIA_STUDIO_507] = {
+               /* Mikhail Fedotov <mo_fedotov@mail.ru> */
+               .name           = "Avermedia AVerTV Studio 507",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1256_IH3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x03,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x00,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+                       .gpio = 0x00,
+               },{
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .gpio = 0x00,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+                       .gpio = 0x00,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x01,
+               },
+               .mute  = {
+                       .name = name_mute,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               },
+       },
+       [SAA7134_BOARD_VIDEOMATE_DVBT_200A] = {
+               /* Francis Barber <fedora@barber-family.id.au> */
+               .name           = "Compro Videomate DVB-T200A",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 3,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 1,
+                       .amux   = LINE2,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
+               /* Thomas Genty <tomlohave@gmail.com> */
+               .name           = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2, /* FIXME: audio doesn't work on svideo/composite */
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux   = TV,
+               },
+       },
+       [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
+               .name           = "Terratec Cinergy HT PCMCIA",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 6,
+                       .amux   = LINE1,
+               }},
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3630,6 +3785,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1043,
                .subdevice    = 0x4860,
                .driver_data  = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x11bd,
+               .subdevice    = 0x002f,
+               .driver_data  = SAA7134_BOARD_PINNACLE_PCTV_310i,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0x9715,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1043,
+               .subdevice    = 0x4876,
+               .driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0070,
+               .subdevice    = 0x6701,
+               .driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x153b,
+               .subdevice    = 0x1172,
+               .driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
        },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -3717,6 +3902,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_307:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
        case SAA7134_BOARD_AVERMEDIA_777:
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
@@ -3725,6 +3911,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_BEHOLD_409FM:
@@ -3793,7 +3980,9 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                break;
        /* i2c remotes */
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                dev->has_remote = SAA7134_REMOTE_I2C;
                break;
        case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -3924,9 +4113,11 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_PHILIPS_TIGER:
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
        case SAA7134_BOARD_TEVION_DVBT_220RF:
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                /* this is a hybrid board, initialize to analog mode
                 * and configure firmware eeprom address
                 */
@@ -3952,6 +4143,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                }
                break;
+       case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+               /* make the tda10046 find its eeprom */
+               {
+               u8 data[] = { 0x3c, 0x33, 0x60};
+               struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+               }
+               break;
        case SAA7134_BOARD_KWORLD_ATSC110:
                {
                        /* enable tuner */
@@ -3964,6 +4163,29 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                                               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,
+                * we are going to query eeprom to try to find out which one we
+                * are actually looking at. */
+
+               /* 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))
+                       break;
+               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;
+                       dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+                       printk(KERN_INFO "%s: Reconfigured board as %s\n",
+                               dev->name, saa7134_boards[dev->board].name);
+               } else {
+                       printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n",
+                               dev->name, dev->eedata[0x41]);
+                       break;
+               }
+               break;
        }
        return 0;
 }
index 5c9e63dfbea6ef3227385e5e1652a0e8caf99e15..ed038fff3b4f80b16feb21021c9508ab83b759b1 100644 (file)
@@ -889,15 +889,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                must_configure_manually();
                dev->board = SAA7134_BOARD_UNKNOWN;
        }
+       dev->autodetected = card[dev->nr] != dev->board;
        dev->tuner_type   = saa7134_boards[dev->board].tuner_type;
        dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
        if (UNSET != tuner[dev->nr])
                dev->tuner_type = tuner[dev->nr];
-       printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
-              dev->name,pci_dev->subsystem_vendor,
-              pci_dev->subsystem_device,saa7134_boards[dev->board].name,
-              dev->board, card[dev->nr] == dev->board ?
-              "insmod option" : "autodetected");
+               printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+               dev->name,pci_dev->subsystem_vendor,
+               pci_dev->subsystem_device,saa7134_boards[dev->board].name,
+               dev->board, dev->autodetected ?
+               "autodetected" : "insmod option");
 
        /* get mmio */
        if (!request_mem_region(pci_resource_start(pci_dev,0),
index 6b61d9b2fcb538f1b97e95a319c7fa8160d13d0f..fa833987909568b586935bb7f124524817c0b253 100644 (file)
@@ -50,6 +50,10 @@ static unsigned int antenna_pwr = 0;
 module_param(antenna_pwr, int, 0444);
 MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
 
+static int use_frontent = 0;
+module_param(use_frontent, int, 0644);
+MODULE_PARM_DESC(use_frontent,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
+
 /* ------------------------------------------------------------------ */
 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
@@ -293,7 +297,7 @@ static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dv
        return philips_tda6651_pll_set(0x60, fe, params);
 }
 
-static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
                                           const struct firmware **fw, char *name)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
@@ -308,7 +312,7 @@ static struct tda1004x_config philips_tu1216_60_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .request_firmware = philips_tu1216_request_firmware,
+       .request_firmware = philips_tda1004x_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
@@ -331,12 +335,12 @@ static struct tda1004x_config philips_tu1216_61_config = {
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .request_firmware = philips_tu1216_request_firmware,
+       .request_firmware = philips_tda1004x_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int philips_europa_tuner_init(struct dvb_frontend *fe)
+static int philips_td1316_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
@@ -347,18 +351,8 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe)
                fe->ops.i2c_gate_ctrl(fe, 1);
        if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
                return -EIO;
-       msleep(1);
-
-       /* switch the board to dvb mode */
-       init_msg.addr = 0x43;
-       init_msg.len  = 0x02;
-       msg[0] = 0x00;
-       msg[1] = 0x40;
        if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
-               return -EIO;
-
+               fe->ops.i2c_gate_ctrl(fe, 0);
        return 0;
 }
 
@@ -367,6 +361,22 @@ static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
        return philips_tda6651_pll_set(0x61, fe, params);
 }
 
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 msg[] = { 0x00, 0x40};
+       struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+       if (philips_td1316_tuner_init(fe))
+               return -EIO;
+       msleep(1);
+       if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
 static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
@@ -671,7 +681,7 @@ static struct tda1004x_config tda827x_lifeview_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
@@ -812,32 +822,40 @@ static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
        return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 {
-       int ret;
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 tda8290_close[] = { 0x21, 0xc0};
        static u8 tda8290_open[]  = { 0x21, 0x80};
        struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
-
-       /* close tda8290 i2c bridge */
-       tda8290_msg.buf = tda8290_close;
-       ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
-       if (ret != 1)
+       if (enable) {
+               tda8290_msg.buf = tda8290_close;
+       } else {
+               tda8290_msg.buf = tda8290_open;
+       }
+       if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1)
                return -EIO;
        msleep(20);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       int ret;
+
        ret = philips_tda827xa_pll_set(0x61, fe, params);
        if (ret != 0)
                return ret;
-       /* open tda8290 i2c bridge */
-       tda8290_msg.buf = tda8290_open;
-       i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
-       return ret;
+       return 0;
 }
 
 static int philips_tiger_tuner_init(struct dvb_frontend *fe)
@@ -867,13 +885,80 @@ static struct tda1004x_config philips_tiger_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
+       .if_freq       = TDA10046_FREQ_045,
+       .request_firmware = NULL,
+};
+/* ------------------------------------------------------------------ */
+
+static int cinergy_ht_tuner_init(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 data[] = { 0x3c, 0x33, 0x62};
+       struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 data[] = { 0x3c, 0x33, 0x60};
+       struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+       philips_tda827xa_tuner_sleep( 0x61, fe);
+       return 0;
+}
+
+static struct tda1004x_config cinergy_ht_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GP01,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
+       .if_freq       = TDA10046_FREQ_045,
+       .request_firmware = philips_tda1004x_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config hauppauge_hvr_1110_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
+       .if_freq       = TDA10046_FREQ_045,
+       .request_firmware = philips_tda1004x_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config asus_p7131_dual_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
+       .if_freq       = TDA10046_FREQ_045,
+       .request_firmware = philips_tda1004x_request_firmware,
+};
+
 static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
@@ -921,7 +1006,7 @@ static struct tda1004x_config lifeview_trio_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X_GPL,
+       .agc_config    = TDA10046_AGC_TDA827X_GP00,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
@@ -958,7 +1043,7 @@ static struct tda1004x_config ads_tech_duo_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X_GPL,
+       .agc_config    = TDA10046_AGC_TDA827X_GP00,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
@@ -983,7 +1068,7 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
@@ -1028,7 +1113,7 @@ static struct tda1004x_config md8800_dvbt_config = {
        .invert        = 1,
        .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_16M,
-       .agc_config    = TDA10046_AGC_TDA827X,
+       .agc_config    = TDA10046_AGC_TDA827X_GP11,
        .if_freq       = TDA10046_FREQ_045,
        .request_firmware = NULL,
 };
@@ -1168,6 +1253,29 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &philips_tiger_config,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+               }
+               break;
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                                              &pinnacle_pctv_310i_config,
+                                              &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+               }
+               break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                                              &hauppauge_hvr_1110_config,
+                                              &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
                        dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
                        dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
                        dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
@@ -1175,9 +1283,10 @@ static int dvb_init(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
                dev->dvb.frontend = dvb_attach(tda10046_attach,
-                                              &philips_tiger_config,
+                                              &asus_p7131_dual_config,
                                               &dev->i2c_adap);
                if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
                        dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init;
                        dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep;
                        dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
@@ -1194,12 +1303,27 @@ static int dvb_init(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_FLYDVB_TRIO:
-               dev->dvb.frontend = dvb_attach(tda10046_attach,
-                                              &lifeview_trio_config,
-                                              &dev->i2c_adap);
-               if (dev->dvb.frontend) {
-                       dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
-                       dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+               if(! use_frontent) {    //terrestrial
+                       dev->dvb.frontend = dvb_attach(tda10046_attach,
+                                                      &lifeview_trio_config,
+                                                      &dev->i2c_adap);
+                       if (dev->dvb.frontend) {
+                               dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+                               dev->dvb.frontend->ops.tuner_ops.set_params =
+                                                               lifeview_trio_tuner_set_params;
+                       }
+               } else {              //satellite
+                       dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+                       if (dev->dvb.frontend) {
+                               if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
+                                                                       &dev->i2c_adap, 0) == NULL) {
+                                       printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+                               }
+                               if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
+                                                                               0x08, 0, 0) == NULL) {
+                                       printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+                               }
+                       }
                }
                break;
        case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
@@ -1281,7 +1405,27 @@ static int dvb_init(struct saa7134_dev *dev)
                        dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
                }
                break;
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                               &philips_europa_config,
+                               &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+               }
+               break;
+       case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+               dev->dvb.frontend = dvb_attach(tda10046_attach,
+                                              &cinergy_ht_config,
+                                              &dev->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+                       dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
+                       dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
+                       dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
 
+               }
+               break;
        default:
                printk("%s: Huh? unknown DVB card?\n",dev->name);
                break;
index 6162550c413604c97069ae751ad5dbd415f0db14..6f9fe86fed9838c26c45bda2ae0759f8de30e124 100644 (file)
@@ -341,6 +341,7 @@ static int attach_inform(struct i2c_client *client)
        switch (client->addr) {
                case 0x7a:
                case 0x47:
+               case 0x71:
                {
                        struct IR_i2c *ir = i2c_get_clientdata(client);
                        d1printk("%s i2c IR detected (%s).\n",
index dee83552e681a26944d1ea0f3403ff88916cc3b2..60b38defd9bccf3d86a1428c7a87dc1544100321 100644 (file)
@@ -112,6 +112,27 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
+static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char buf[5], cod4, code3, code4;
+
+       /* poll IR chip */
+       if (5 != i2c_master_recv(&ir->c,buf,5))
+               return -EIO;
+
+       cod4    = buf[4];
+       code4   = (cod4 >> 2);
+       code3   = buf[3];
+       if (code3 == 0)
+               /* no key pressed */
+               return 0;
+
+       /* return key */
+       *ir_key = code4;
+       *ir_raw = code4;
+       return 1;
+}
+
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
        struct saa7134_ir *ir = dev->remote;
@@ -131,6 +152,23 @@ static void saa7134_input_timer(unsigned long data)
        mod_timer(&ir->timer, timeout);
 }
 
+static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
+{
+       if (ir->polling) {
+               init_timer(&ir->timer);
+               ir->timer.function = saa7134_input_timer;
+               ir->timer.data     = (unsigned long)dev;
+               ir->timer.expires  = jiffies + HZ;
+               add_timer(&ir->timer);
+       }
+}
+
+static void saa7134_ir_stop(struct saa7134_dev *dev)
+{
+       if (dev->remote->polling)
+               del_timer_sync(&dev->remote->timer);
+}
+
 int saa7134_input_init1(struct saa7134_dev *dev)
 {
        struct saa7134_ir *ir;
@@ -141,6 +179,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        u32 mask_keyup   = 0;
        int polling      = 0;
        int ir_type      = IR_TYPE_OTHER;
+       int err;
 
        if (dev->has_remote != SAA7134_REMOTE_GPIO)
                return -ENODEV;
@@ -184,6 +223,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
                ir_codes     = ir_codes_avermedia;
                mask_keycode = 0x0007C8;
@@ -266,9 +306,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!ir || !input_dev) {
-               kfree(ir);
-               input_free_device(input_dev);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_out_free;
        }
 
        ir->dev = input_dev;
@@ -299,18 +338,22 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        }
        input_dev->cdev.dev = &dev->pci->dev;
 
-       /* all done */
        dev->remote = ir;
-       if (ir->polling) {
-               init_timer(&ir->timer);
-               ir->timer.function = saa7134_input_timer;
-               ir->timer.data     = (unsigned long)dev;
-               ir->timer.expires  = jiffies + HZ;
-               add_timer(&ir->timer);
-       }
+       saa7134_ir_start(dev, ir);
+
+       err = input_register_device(ir->dev);
+       if (err)
+               goto err_out_stop;
 
-       input_register_device(ir->dev);
        return 0;
+
+ err_out_stop:
+       saa7134_ir_stop(dev);
+       dev->remote = NULL;
+ err_out_free:
+       input_free_device(input_dev);
+       kfree(ir);
+       return err;
 }
 
 void saa7134_input_fini(struct saa7134_dev *dev)
@@ -318,8 +361,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
        if (NULL == dev->remote)
                return;
 
-       if (dev->remote->polling)
-               del_timer_sync(&dev->remote->timer);
+       saa7134_ir_stop(dev);
        input_unregister_device(dev->remote->dev);
        kfree(dev->remote);
        dev->remote = NULL;
@@ -335,6 +377,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
 
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
+       case SAA7134_BOARD_PINNACLE_PCTV_310i:
                snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
                if (pinnacle_remote == 0) {
                        ir->get_key   = get_key_pinnacle_color;
@@ -349,6 +392,11 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
                ir->get_key   = get_key_purpletv;
                ir->ir_codes  = ir_codes_purpletv;
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+               snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
+               ir->get_key   = get_key_hvr1110;
+               ir->ir_codes  = ir_codes_hauppauge_new;
+               break;
        default:
                dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
                break;
index 7cf96b430250013710409a118578d5129822b51a..e88ad7b40c47be8880adfed0c15b6eda922526c7 100644 (file)
@@ -227,6 +227,11 @@ struct saa7134_format {
 #define SAA7134_BOARD_PROTEUS_2309 98
 #define SAA7134_BOARD_AVERMEDIA_A16AR   99
 #define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+#define SAA7134_BOARD_PINNACLE_PCTV_310i  101
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200A  103
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110    104
+#define SAA7134_BOARD_CINERGY_HT_PCMCIA    105
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -446,6 +451,9 @@ struct saa7134_dev {
        struct v4l2_prio_state     prio;
 #endif
 
+       /* insmod option/autodetected */
+       int                        autodetected;
+
        /* various device info */
        unsigned int               resources;
        struct video_device        *video_dev;
index 6d1ef1e2e8efd9dbf8be48763ee7283b3cf42021..a1ec3aca3f918b7ecf816eb81667b087cba69e5e 100644 (file)
@@ -687,7 +687,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
                stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
                if (stv680->sbuf[i].data == NULL) {
                        PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
-                       return -1;
+                       goto nomem_err;
                }
        }
 
@@ -698,7 +698,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
                stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
                if (stv680->scratch[i].data == NULL) {
                        PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
-                       return -1;
+                       goto nomem_err;
                }
                stv680->scratch[i].state = BUFFER_UNUSED;
        }
@@ -706,7 +706,7 @@ static int stv680_start_stream (struct usb_stv *stv680)
        for (i = 0; i < STV680_NUMSBUF; i++) {
                urb = usb_alloc_urb (0, GFP_KERNEL);
                if (!urb)
-                       return -ENOMEM;
+                       goto nomem_err;
 
                /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
                usb_fill_bulk_urb (urb, stv680->udev,
@@ -721,6 +721,21 @@ static int stv680_start_stream (struct usb_stv *stv680)
 
        stv680->framecount = 0;
        return 0;
+
+ nomem_err:
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               kfree(stv680->scratch[i].data);
+               stv680->scratch[i].data = NULL;
+       }
+       for (i = 0; i < STV680_NUMSBUF; i++) {
+               usb_kill_urb(stv680->urb[i]);
+               usb_free_urb(stv680->urb[i]);
+               stv680->urb[i] = NULL;
+               kfree(stv680->sbuf[i].data);
+               stv680->sbuf[i].data = NULL;
+       }
+       return -ENOMEM;
+
 }
 
 static int stv680_stop_stream (struct usb_stv *stv680)
index 87ffb0e84a7a063cd34589d8705e00d1a9b1b28b..fde576f1101cb3f980c9cb616aa3ae7ee1be48c3 100644 (file)
@@ -482,6 +482,12 @@ static int tda9887_set_config(struct tuner *t, char *buf)
                buf[1] &= ~cQSS;
        if (t->tda9887_config & TDA9887_GATING_18)
                buf[3] &= ~cGating_36;
+
+       if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
+               radio_stereo.e &= ~cTunerGainLow;
+               radio_mono.e &= ~cTunerGainLow;
+       }
+
        return 0;
 }
 
index 40590bae5ff7f55652ae57039d9347ccbb6f8566..705daaa2a4ff82a649c19affa1f7c02a2b9c3152 100644 (file)
@@ -443,6 +443,10 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
                        printk("%02x ",buffer[i]);
                printk("\n");
        }
+       /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
+       if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
+               return -ENODEV;
+
        /* autodetection code based on the i2c addr */
        if (!no_autodetect) {
                switch (addr) {
index 63db4e97ae6ce57a6003d55b0b0c6a187cc46e6e..1b9b0742f753f53c181391b24eceac1b88d6e3c9 100644 (file)
@@ -108,6 +108,7 @@ static int tuner_stereo(struct i2c_client *c)
                case TUNER_PHILIPS_FM1216ME_MK3:
                case TUNER_PHILIPS_FM1236_MK3:
                case TUNER_PHILIPS_FM1256_IH3:
+               case TUNER_LG_NTSC_TAPE:
                        stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
                        break;
                default:
@@ -421,6 +422,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
        case TUNER_PHILIPS_FM1216ME_MK3:
        case TUNER_PHILIPS_FM1236_MK3:
        case TUNER_PHILIPS_FMD1216ME_MK3:
+       case TUNER_LG_NTSC_TAPE:
                buffer[3] = 0x19;
                break;
        case TUNER_TNF_5335MF:
@@ -465,6 +467,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
                        config |= TDA9887_INTERCARRIER;
 /*             if (params->port1_set_for_fm_mono)
                        config &= ~TDA9887_PORT1_ACTIVE;*/
+               if (params->fm_gain_normal)
+                       config |= TDA9887_GAIN_NORMAL;
                i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
        }
        if (4 != (rc = i2c_master_send(c,buffer,4)))
index 781682373b61f3992d36ac9e938a62451cd61608..74c3e6f96f1a7b0846b93d57938c3d1788e7011e 100644 (file)
@@ -651,6 +651,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
                .has_tda9887 = 1,
                .port1_invert_for_secam_lc = 1,
                .default_pll_gating_18 = 1,
+               .fm_gain_normal=1,
        },
 };
 
@@ -672,16 +673,6 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
        },
 };
 
-/* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */
-
-static struct tuner_params tuner_lg_ntsc_tape_params[] = {
-       {
-               .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_fm1236_mk3_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-       },
-};
-
 /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
 
 static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
@@ -1331,8 +1322,8 @@ struct tunertype tuners[] = {
        },
        [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
                .name   = "LG NTSC (TAPE series)",
-               .params = tuner_lg_ntsc_tape_params,
-               .count  = ARRAY_SIZE(tuner_lg_ntsc_tape_params),
+               .params = tuner_fm1236_mk3_params,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
        },
        [TUNER_TNF_8831BGFF] = { /* Philips PAL */
                .name   = "Tenna TNF 8831 BGFF)",
index 6b9ef731b83aabc917bb64d6a4a5823791c7b2a2..2624e3f7dd29e2763fdd82406d7ea4a4cdedd5d8 100644 (file)
@@ -430,7 +430,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        tvee->has_radio = eeprom_data[i+len-1];
                        /* old style tag, don't know how to detect
                        IR presence, mark as unknown. */
-                       tvee->has_ir = 2;
+                       tvee->has_ir = -1;
                        tvee->model =
                                eeprom_data[i+8] +
                                (eeprom_data[i+9] << 8);
@@ -653,13 +653,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        STRM(decoderIC, tvee->decoder_processor),
                        tvee->decoder_processor);
        }
-       if (tvee->has_ir == 2)
+       if (tvee->has_ir == -1)
                tveeprom_info("has %sradio\n",
                                tvee->has_radio ? "" : "no ");
        else
-               tveeprom_info("has %sradio, has %sIR remote\n",
+               tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n",
                                tvee->has_radio ? "" : "no ",
-                               tvee->has_ir ? "" : "no ");
+                               (tvee->has_ir & 1) ? "" : "no ",
+                               (tvee->has_ir & 2) ? "" : "no ");
 }
 EXPORT_SYMBOL(tveeprom_hauppauge_analog);
 
index bbf2beeeb449bd215fe45317a2448e359127981a..ec0ff2247f06a6c74c8382640b913903e7c96cc7 100644 (file)
@@ -86,6 +86,7 @@ MODULE_DEVICE_TABLE(usb, qcm_table);
 static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
 {
        struct input_dev *input_dev;
+       int error;
 
        usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
        strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
@@ -106,7 +107,13 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
 
        input_dev->private = cam;
 
-       input_register_device(cam->input);
+       error = input_register_device(cam->input);
+       if (error) {
+               warn("Failed to register camera's input device, err: %d\n",
+                    error);
+               input_free_device(cam->input);
+               cam->input = NULL;
+       }
 }
 
 static void qcm_unregister_input(struct qcm *cam)
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
new file mode 100644 (file)
index 0000000..fc24ef0
--- /dev/null
@@ -0,0 +1,12 @@
+config VIDEO_USBVISION
+       tristate "USB video devices based on Nogatech NT1003/1004/1005"
+       depends on I2C && VIDEO_V4L2
+       select VIDEO_TUNER
+       select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+       ---help---
+         There are more than 50 different USB video devices based on
+         NT1003/1004/1005 USB Bridges. This driver enables using those
+         devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called usbvision.
diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile
new file mode 100644 (file)
index 0000000..9ac92a8
--- /dev/null
@@ -0,0 +1,5 @@
+usbvision-objs  := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o
+
+obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
new file mode 100644 (file)
index 0000000..134eb98
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * USBVISION.H
+ *  usbvision header file
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * 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/list.h>
+#include <linux/i2c.h>
+#include <media/v4l2-dev.h>
+#include <media/tuner.h>
+#include "usbvision.h"
+
+/* Supported Devices: A table for usbvision.c*/
+struct usbvision_device_data_st  usbvision_device_data[] = {
+       {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"},
+       {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "Xanboo"},
+       {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Belkin USBView II"},
+       {0x0571, 0x0002,  0, CODEC_SAA7111, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1, -1, -1,  7, "echoFX InterView Lite"},
+       {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"},
+       {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC,  0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "D-Link V100"},
+       {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "X10 USB Camera"},
+       {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1, -1,  3,  7, "Osprey 50"},
+       {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC,    0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Hauppauge USB-Live Model 600"},
+       {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,     2, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"},
+       {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"},
+       {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"},
+       {0x0573, 0x4450,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "PixelView PlayTv-USB PRO (PAL) FM"},
+       {0x0573, 0x4550,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "ZTV ZT-721 2.4GHz USB A/V Receiver"},
+       {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"},
+       {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
+       {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"},
+       {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "},
+       {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"},
+       {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
+       {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
+       {0x0573, 0x4d2a,  0, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"},
+       {0x0573, 0x4d2b,  0, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"},
+       {0x0573, 0x4d2c,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1,  0,  3,  7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"},
+       {0x0573, 0x4d20,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"},
+       {0x0573, 0x4d21,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL)"},
+       {0x0573, 0x4d22,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL) MODEL 566"},
+       {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) 4D23"},
+       {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"},
+       {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"},
+       {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40204 Rev B281"},
+       {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40204 Rev B283"},
+       {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40205 Rev B298"},
+       {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"},
+       {0x0573, 0x4d31,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 568"},
+       {0x0573, 0x4d32,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 573"},
+       {0x0573, 0x4d35,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"},
+       {0x0573, 0x4d37,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1,  0,  3,  7, "Hauppauge WinTV USB device Model 40219 Rev E189"},
+       {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1,  5,  5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"},
+       {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Digital Video Creator I"},
+       {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  0, 0, 1, 0, 0,                            -1, -1, 82, 20,  7, "Global Village GV-007 (NTSC)"},
+       {0x07d0, 0x0003,  0, CODEC_SAA7113, 2, V4L2_STD_NTSC,  0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"},
+       {0x07d0, 0x0004,  0, CODEC_SAA7113, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"},
+       {0x07d0, 0x0005,  0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0,                            -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"},
+       {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I,  -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"},
+       {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"},
+       {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"},
+       {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Miro PCTV USB"},
+       {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"},
+       {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (PAL) FM"},
+       {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC,   -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (NTSC) FM"},
+       {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (PAL) FM"},
+       {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Pinnacle Studio Linx Video input cable (NTSC)"},
+       {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Pinnacle Studio Linx Video input cable (PAL)"},
+       {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle PCTV Bungee USB (PAL) FM"},
+       {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
+       {}  /* Terminating entry */
+};
+
+/* Supported Devices */
+
+struct usb_device_id usbvision_table [] = {
+       { USB_DEVICE(0xFFF0, 0xFFF0) },  /* Custom Dummy USBVision Device */
+       { USB_DEVICE(0x0A6F, 0x0400) },  /* Xanboo */
+       { USB_DEVICE(0x050d, 0x0208) },  /* Belkin USBView II */
+       { USB_DEVICE(0x0571, 0x0002) },  /* echoFX InterView Lite */
+       { USB_DEVICE(0x0573, 0x0003) },  /* USBGear USBG-V1 */
+       { USB_DEVICE(0x0573, 0x0400) },  /* D-Link V100 */
+       { USB_DEVICE(0x0573, 0x2000) },  /* X10 USB Camera */
+       { USB_DEVICE(0x0573, 0x2d00) },  /* Osprey 50 */
+       { USB_DEVICE(0x0573, 0x2d01) },  /* Hauppauge USB-Live Model 600 */
+       { USB_DEVICE(0x0573, 0x2101) },  /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */
+       { USB_DEVICE(0x0573, 0x4100) },  /* Nogatech USB-TV FM (NTSC) */
+       { USB_DEVICE(0x0573, 0x4110) },  /* PNY USB-TV (NTSC) FM */
+       { USB_DEVICE(0x0573, 0x4450) },  /* PixelView PlayTv-USB PRO (PAL) FM */
+       { USB_DEVICE(0x0573, 0x4550) },  /* ZTV ZT-721 2.4GHz USB A/V Receiver */
+       { USB_DEVICE(0x0573, 0x4d00) },  /* Hauppauge WinTv-USB USA */
+       { USB_DEVICE(0x0573, 0x4d01) },  /* Hauppauge WinTv-USB */
+       { USB_DEVICE(0x0573, 0x4d02) },  /* Hauppauge WinTv-USB UK */
+       { USB_DEVICE(0x0573, 0x4d03) },  /* Hauppauge WinTv-USB France */
+       { USB_DEVICE(0x0573, 0x4d10) },  /* Hauppauge WinTv-USB with FM USA radio */
+       { USB_DEVICE(0x0573, 0x4d11) },  /* Hauppauge WinTv-USB (PAL) with FM radio */
+       { USB_DEVICE(0x0573, 0x4d12) },  /* Hauppauge WinTv-USB UK with FM Radio */
+       { USB_DEVICE(0x0573, 0x4d2a) },  /* Hauppague WinTv USB Model 602 40201 Rev B285 */
+       { USB_DEVICE(0x0573, 0x4d2b) },  /* Hauppague WinTv USB Model 602 40201 Rev B282 */
+       { USB_DEVICE(0x0573, 0x4d2c) },  /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/
+       { USB_DEVICE(0x0573, 0x4d20) },  /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */
+       { USB_DEVICE(0x0573, 0x4d21) },  /* Hauppauge WinTv-USB II (PAL) with FM radio*/
+       { USB_DEVICE(0x0573, 0x4d22) },  /* Hauppauge WinTv-USB II (PAL) Model 566 */
+       { USB_DEVICE(0x0573, 0x4d23) },  /* Hauppauge WinTv-USB France 4D23*/
+       { USB_DEVICE(0x0573, 0x4d25) },  /* Hauppauge WinTv-USB Model 40209 rev B234 */
+       { USB_DEVICE(0x0573, 0x4d26) },  /* Hauppauge WinTv-USB Model 40209 Rev B243 */
+       { USB_DEVICE(0x0573, 0x4d27) },  /* Hauppauge WinTv-USB Model 40204 Rev B281 */
+       { USB_DEVICE(0x0573, 0x4d28) },  /* Hauppauge WinTv-USB Model 40204 Rev B283 */
+       { USB_DEVICE(0x0573, 0x4d29) },  /* Hauppauge WinTv-USB Model 40205 Rev B298 */
+       { USB_DEVICE(0x0573, 0x4d30) },  /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */
+       { USB_DEVICE(0x0573, 0x4d31) },  /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */
+       { USB_DEVICE(0x0573, 0x4d32) },  /* Hauppauge WinTv-USB III (PAL) FM Model 573 */
+       { USB_DEVICE(0x0573, 0x4d35) },  /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */
+       { USB_DEVICE(0x0573, 0x4d37) },  /* Hauppauge WinTv-USB Model 40219 Rev E189 */
+       { USB_DEVICE(0x0768, 0x0006) },  /* Camtel Technology USB TV Genie Pro FM Model TVB330 */
+       { USB_DEVICE(0x07d0, 0x0001) },  /* Digital Video Creator I */
+       { USB_DEVICE(0x07d0, 0x0002) },  /* Global Village GV-007 (NTSC) */
+       { USB_DEVICE(0x07d0, 0x0003) },  /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */
+       { USB_DEVICE(0x07d0, 0x0004) },  /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */
+       { USB_DEVICE(0x07d0, 0x0005) },  /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */
+       { USB_DEVICE(0x2304, 0x010d) },  /* Pinnacle Studio PCTV USB (PAL) */
+       { USB_DEVICE(0x2304, 0x0109) },  /* Pinnacle Studio PCTV USB (SECAM) */
+       { USB_DEVICE(0x2304, 0x0110) },  /* Pinnacle Studio PCTV USB (PAL) */
+       { USB_DEVICE(0x2304, 0x0111) },  /* Miro PCTV USB */
+       { USB_DEVICE(0x2304, 0x0112) },  /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
+       { USB_DEVICE(0x2304, 0x0210) },  /* Pinnacle Studio PCTV USB (PAL) with FM radio */
+       { USB_DEVICE(0x2304, 0x0212) },  /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
+       { USB_DEVICE(0x2304, 0x0214) },  /* Pinnacle Studio PCTV USB (PAL) with FM radio */
+       { USB_DEVICE(0x2304, 0x0300) },  /* Pinnacle Studio Linx Video input cable (NTSC) */
+       { USB_DEVICE(0x2304, 0x0301) },  /* Pinnacle Studio Linx Video input cable (PAL) */
+       { USB_DEVICE(0x2304, 0x0419) },  /* Pinnacle PCTV Bungee USB (PAL) FM */
+
+       { USB_DEVICE(0x2400, 0x4200) },  /* Hauppauge WinTv-USB2 Model 42012 */
+
+       { }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
new file mode 100644 (file)
index 0000000..797b97b
--- /dev/null
@@ -0,0 +1,2554 @@
+/*
+ * usbvision-core.c - driver for NT100x USB video capture devices
+ *
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *                         Dwaine Garden <dwainegarden@rogers.com>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * 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/sched.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#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>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "usbvision.h"
+
+static unsigned int core_debug = 0;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int force_testpattern = 0;
+module_param(force_testpattern,int,0644);
+MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");
+
+static int adjustCompression = 1;                      // Set the compression to be adaptive
+module_param(adjustCompression, int, 0444);
+MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device.  Default: 1 (On)");
+
+static int SwitchSVideoInput = 0;                      // To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
+module_param(SwitchSVideoInput, int, 0444);
+MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
+
+#define        ENABLE_HEXDUMP  0       /* Enable if you need it */
+
+
+#ifdef USBVISION_DEBUG
+       #define PDEBUG(level, fmt, args...) \
+               if (core_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+       #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+#define DBG_HEADER     1<<0
+#define DBG_IRQ                1<<1
+#define DBG_ISOC       1<<2
+#define DBG_PARSE      1<<3
+#define DBG_SCRATCH    1<<4
+#define DBG_FUNC       1<<5
+
+static const int max_imgwidth = MAX_FRAME_WIDTH;
+static const int max_imgheight = MAX_FRAME_HEIGHT;
+static const int min_imgwidth = MIN_FRAME_WIDTH;
+static const int min_imgheight = MIN_FRAME_HEIGHT;
+
+/* The value of 'scratch_buf_size' affects quality of the picture
+ * in many ways. Shorter buffers may cause loss of data when client
+ * is too slow. Larger buffers are memory-consuming and take longer
+ * to work with. This setting can be adjusted, but the default value
+ * should be OK for most desktop users.
+ */
+#define DEFAULT_SCRATCH_BUF_SIZE       (0x20000)               // 128kB memory scratch buffer
+static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;
+
+// Function prototypes
+static int usbvision_request_intra (struct usb_usbvision *usbvision);
+static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);
+static int usbvision_adjust_compression (struct usb_usbvision *usbvision);
+static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+/*
+ * Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
+ */
+
+void *usbvision_rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+void usbvision_rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       size = PAGE_ALIGN(size);
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vfree(mem);
+}
+
+
+
+#if ENABLE_HEXDUMP
+static void usbvision_hexdump(const unsigned char *data, int len)
+{
+       char tmp[80];
+       int i, k;
+
+       for (i = k = 0; len > 0; i++, len--) {
+               if (i > 0 && (i % 16 == 0)) {
+                       printk("%s\n", tmp);
+                       k = 0;
+               }
+               k += sprintf(&tmp[k], "%02x ", data[i]);
+       }
+       if (k > 0)
+               printk("%s\n", tmp);
+}
+#endif
+
+/********************************
+ * scratch ring buffer handling
+ ********************************/
+int scratch_len(struct usb_usbvision *usbvision)    /*This returns the amount of data actually in the buffer */
+{
+       int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr;
+       if (len < 0) {
+               len += scratch_buf_size;
+       }
+       PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len);
+
+       return len;
+}
+
+
+/* This returns the free space left in the buffer */
+int scratch_free(struct usb_usbvision *usbvision)
+{
+       int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr;
+       if (free <= 0) {
+               free += scratch_buf_size;
+       }
+       if (free) {
+               free -= 1;                                                      /* at least one byte in the buffer must */
+                                                                               /* left blank, otherwise there is no chance to differ between full and empty */
+       }
+       PDEBUG(DBG_SCRATCH, "return %d\n", free);
+
+       return free;
+}
+
+
+/* This puts data into the buffer */
+int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len)
+{
+       int len_part;
+
+       if (usbvision->scratch_write_ptr + len < scratch_buf_size) {
+               memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len);
+               usbvision->scratch_write_ptr += len;
+       }
+       else {
+               len_part = scratch_buf_size - usbvision->scratch_write_ptr;
+               memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part);
+               if (len == len_part) {
+                       usbvision->scratch_write_ptr = 0;                       /* just set write_ptr to zero */
+               }
+               else {
+                       memcpy(usbvision->scratch, data + len_part, len - len_part);
+                       usbvision->scratch_write_ptr = len - len_part;
+               }
+       }
+
+       PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr);
+
+       return len;
+}
+
+/* This marks the write_ptr as position of new frame header */
+void scratch_mark_header(struct usb_usbvision *usbvision)
+{
+       PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr);
+
+       usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] =
+                               usbvision->scratch_write_ptr;
+       usbvision->scratch_headermarker_write_ptr += 1;
+       usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER;
+}
+
+/* This gets data from the buffer at the given "ptr" position */
+int scratch_get_extra(struct usb_usbvision *usbvision, unsigned char *data, int *ptr, int len)
+{
+       int len_part;
+       if (*ptr + len < scratch_buf_size) {
+               memcpy(data, usbvision->scratch + *ptr, len);
+               *ptr += len;
+       }
+       else {
+               len_part = scratch_buf_size - *ptr;
+               memcpy(data, usbvision->scratch + *ptr, len_part);
+               if (len == len_part) {
+                       *ptr = 0;                                                       /* just set the y_ptr to zero */
+               }
+               else {
+                       memcpy(data + len_part, usbvision->scratch, len - len_part);
+                       *ptr = len - len_part;
+               }
+       }
+
+       PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr);
+
+       return len;
+}
+
+
+/* This sets the scratch extra read pointer */
+void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, int len)
+{
+       *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size;
+
+       PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
+}
+
+
+/*This increments the scratch extra read pointer */
+void scratch_inc_extra_ptr(int *ptr, int len)
+{
+       *ptr = (*ptr + len) % scratch_buf_size;
+
+       PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
+}
+
+
+/* This gets data from the buffer */
+int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, int len)
+{
+       int len_part;
+       if (usbvision->scratch_read_ptr + len < scratch_buf_size) {
+               memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len);
+               usbvision->scratch_read_ptr += len;
+       }
+       else {
+               len_part = scratch_buf_size - usbvision->scratch_read_ptr;
+               memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part);
+               if (len == len_part) {
+                       usbvision->scratch_read_ptr = 0;                                /* just set the read_ptr to zero */
+               }
+               else {
+                       memcpy(data + len_part, usbvision->scratch, len - len_part);
+                       usbvision->scratch_read_ptr = len - len_part;
+               }
+       }
+
+       PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr);
+
+       return len;
+}
+
+
+/* This sets read pointer to next header and returns it */
+int scratch_get_header(struct usb_usbvision *usbvision,struct usbvision_frame_header *header)
+{
+       int errCode = 0;
+
+       PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr);
+
+       while (usbvision->scratch_headermarker_write_ptr -
+               usbvision->scratch_headermarker_read_ptr != 0) {
+               usbvision->scratch_read_ptr =
+                       usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr];
+               usbvision->scratch_headermarker_read_ptr += 1;
+               usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER;
+               scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH);
+               if ((header->magic_1 == USBVISION_MAGIC_1)
+                        && (header->magic_2 == USBVISION_MAGIC_2)
+                        && (header->headerLength == USBVISION_HEADER_LENGTH)) {
+                       errCode = USBVISION_HEADER_LENGTH;
+                       header->frameWidth  = header->frameWidthLo  + (header->frameWidthHi << 8);
+                       header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8);
+                       break;
+               }
+       }
+
+       return errCode;
+}
+
+
+/*This removes len bytes of old data from the buffer */
+void scratch_rm_old(struct usb_usbvision *usbvision, int len)
+{
+
+       usbvision->scratch_read_ptr += len;
+       usbvision->scratch_read_ptr %= scratch_buf_size;
+       PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);
+}
+
+
+/*This resets the buffer - kills all data in it too */
+void scratch_reset(struct usb_usbvision *usbvision)
+{
+       PDEBUG(DBG_SCRATCH, "\n");
+
+       usbvision->scratch_read_ptr = 0;
+       usbvision->scratch_write_ptr = 0;
+       usbvision->scratch_headermarker_read_ptr = 0;
+       usbvision->scratch_headermarker_write_ptr = 0;
+       usbvision->isocstate = IsocState_NoFrame;
+}
+
+int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
+{
+       usbvision->scratch = vmalloc(scratch_buf_size);
+       scratch_reset(usbvision);
+       if(usbvision->scratch == NULL) {
+               err("%s: unable to allocate %d bytes for scratch",
+                   __FUNCTION__, scratch_buf_size);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void usbvision_scratch_free(struct usb_usbvision *usbvision)
+{
+       if (usbvision->scratch != NULL) {
+               vfree(usbvision->scratch);
+               usbvision->scratch = NULL;
+       }
+}
+
+/*
+ * usbvision_testpattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe:   if TRUE then entire frame is filled, otherwise the procedure
+ *             continues from the current scanline.
+ * pmode       0: fill the frame with solid blue color (like on VCR or TV)
+ *             1: Draw a colored grid
+ *
+ */
+void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe,
+                       int pmode)
+{
+       static const char proc[] = "usbvision_testpattern";
+       struct usbvision_frame *frame;
+       unsigned char *f;
+       int num_cell = 0;
+       int scan_length = 0;
+       static int num_pass = 0;
+
+       if (usbvision == NULL) {
+               printk(KERN_ERR "%s: usbvision == NULL\n", proc);
+               return;
+       }
+       if (usbvision->curFrame == NULL) {
+               printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);
+               return;
+       }
+
+       /* Grab the current frame */
+       frame = usbvision->curFrame;
+
+       /* Optionally start at the beginning */
+       if (fullframe) {
+               frame->curline = 0;
+               frame->scanlength = 0;
+       }
+
+       /* Form every scan line */
+       for (; frame->curline < frame->frmheight; frame->curline++) {
+               int i;
+
+               f = frame->data + (usbvision->curwidth * 3 * frame->curline);
+               for (i = 0; i < usbvision->curwidth; i++) {
+                       unsigned char cb = 0x80;
+                       unsigned char cg = 0;
+                       unsigned char cr = 0;
+
+                       if (pmode == 1) {
+                               if (frame->curline % 32 == 0)
+                                       cb = 0, cg = cr = 0xFF;
+                               else if (i % 32 == 0) {
+                                       if (frame->curline % 32 == 1)
+                                               num_cell++;
+                                       cb = 0, cg = cr = 0xFF;
+                               } else {
+                                       cb =
+                                           ((num_cell * 7) +
+                                            num_pass) & 0xFF;
+                                       cg =
+                                           ((num_cell * 5) +
+                                            num_pass * 2) & 0xFF;
+                                       cr =
+                                           ((num_cell * 3) +
+                                            num_pass * 3) & 0xFF;
+                               }
+                       } else {
+                               /* Just the blue screen */
+                       }
+
+                       *f++ = cb;
+                       *f++ = cg;
+                       *f++ = cr;
+                       scan_length += 3;
+               }
+       }
+
+       frame->grabstate = FrameState_Done;
+       frame->scanlength += scan_length;
+       ++num_pass;
+
+}
+
+/*
+ * usbvision_decompress_alloc()
+ *
+ * allocates intermediate buffer for decompression
+ */
+int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
+{
+       int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
+       usbvision->IntraFrameBuffer = vmalloc(IFB_size);
+       if (usbvision->IntraFrameBuffer == NULL) {
+               err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/*
+ * usbvision_decompress_free()
+ *
+ * frees intermediate buffer for decompression
+ */
+void usbvision_decompress_free(struct usb_usbvision *usbvision)
+{
+       if (usbvision->IntraFrameBuffer != NULL) {
+               vfree(usbvision->IntraFrameBuffer);
+               usbvision->IntraFrameBuffer = NULL;
+       }
+}
+
+/************************************************************
+ * Here comes the data parsing stuff that is run as interrupt
+ ************************************************************/
+/*
+ * usbvision_find_header()
+ *
+ * Locate one of supported header markers in the scratch buffer.
+ */
+static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
+{
+       struct usbvision_frame *frame;
+       int foundHeader = 0;
+
+       frame = usbvision->curFrame;
+
+       while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {
+               // found header in scratch
+               PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u",
+                               frame->isocHeader.magic_2,
+                               frame->isocHeader.magic_1,
+                               frame->isocHeader.headerLength,
+                               frame->isocHeader.frameNum,
+                               frame->isocHeader.framePhase,
+                               frame->isocHeader.frameLatency,
+                               frame->isocHeader.dataFormat,
+                               frame->isocHeader.formatParam,
+                               frame->isocHeader.frameWidth,
+                               frame->isocHeader.frameHeight);
+
+               if (usbvision->requestIntra) {
+                       if (frame->isocHeader.formatParam & 0x80) {
+                               foundHeader = 1;
+                               usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time
+                               usbvision_unrequest_intra(usbvision);
+                               break;
+                       }
+               }
+               else {
+                       foundHeader = 1;
+                       break;
+               }
+       }
+
+       if (foundHeader) {
+               frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;
+               frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;
+               frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;
+       }
+       else { // no header found
+               PDEBUG(DBG_HEADER, "skipping scratch data, no header");
+               scratch_reset(usbvision);
+               return ParseState_EndParse;
+       }
+
+       // found header
+       if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) {
+               //check isocHeader.frameNum for lost frames
+               if (usbvision->lastIsocFrameNum >= 0) {
+                       if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) {
+                               // unexpected frame drop: need to request new intra frame
+                               PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum);
+                               usbvision_request_intra(usbvision);
+                               return ParseState_NextFrame;
+                       }
+               }
+               usbvision->lastIsocFrameNum = frame->isocHeader.frameNum;
+       }
+       usbvision->header_count++;
+       frame->scanstate = ScanState_Lines;
+       frame->curline = 0;
+
+       if (force_testpattern) {
+               usbvision_testpattern(usbvision, 1, 1);
+               return ParseState_NextFrame;
+       }
+       return ParseState_Continue;
+}
+
+static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision,
+                                          long *pcopylen)
+{
+       volatile struct usbvision_frame *frame;
+       unsigned char *f;
+       int len;
+       int i;
+       unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components
+       unsigned char rv, gv, bv;       // RGB components
+       int clipmask_index, bytes_per_pixel;
+       int stretch_bytes, clipmask_add;
+
+       frame  = usbvision->curFrame;
+       f = frame->data + (frame->v4l2_linesize * frame->curline);
+
+       /* Make sure there's enough data for the entire line */
+       len = (frame->isocHeader.frameWidth * 2)+5;
+       if (scratch_len(usbvision) < len) {
+               PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len);
+               return ParseState_Out;
+       }
+
+       if ((frame->curline + 1) >= frame->frmheight) {
+               return ParseState_NextFrame;
+       }
+
+       bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+       stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
+       clipmask_index = frame->curline * MAX_FRAME_WIDTH;
+       clipmask_add = usbvision->stretch_width;
+
+       for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) {
+
+               scratch_get(usbvision, &yuyv[0], 4);
+
+               if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                       *f++ = yuyv[0]; // Y
+                       *f++ = yuyv[3]; // U
+               }
+               else {
+
+                       YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
+                       switch (frame->v4l2_format.format) {
+                               case V4L2_PIX_FMT_RGB565:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       f++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+                                       break;
+                       }
+               }
+               clipmask_index += clipmask_add;
+               f += stretch_bytes;
+
+               if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                       *f++ = yuyv[2]; // Y
+                       *f++ = yuyv[1]; // V
+               }
+               else {
+
+                       YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
+                       switch (frame->v4l2_format.format) {
+                               case V4L2_PIX_FMT_RGB565:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       f++;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+                                       break;
+                       }
+               }
+               clipmask_index += clipmask_add;
+               f += stretch_bytes;
+       }
+
+       frame->curline += usbvision->stretch_height;
+       *pcopylen += frame->v4l2_linesize * usbvision->stretch_height;
+
+       if (frame->curline >= frame->frmheight) {
+               return ParseState_NextFrame;
+       }
+       else {
+               return ParseState_Continue;
+       }
+}
+
+/* The decompression routine  */
+static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed,
+                                                               unsigned char *Decompressed, int *StartPos,
+                                                               int *BlockTypeStartPos, int Len)
+{
+       int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen;
+       unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator;
+
+       Integrator = 0;
+       Pos = *StartPos;
+       BlockTypePos = *BlockTypeStartPos;
+       MaxPos = 396; //Pos + Len;
+       ExtraPos = Pos;
+       BlockLen = 0;
+       BlockByte = 0;
+       BlockCode = 0;
+       BlockType = 0;
+       BlockTypeByte = 0;
+       BlockTypeLen = 0;
+       RestPixel = Len;
+
+       for (Idx = 0; Idx < Len; Idx++) {
+
+               if (BlockLen == 0) {
+                       if (BlockTypeLen==0) {
+                               BlockTypeByte = Compressed[BlockTypePos];
+                               BlockTypePos++;
+                               BlockTypeLen = 4;
+                       }
+                       BlockType = (BlockTypeByte & 0xC0) >> 6;
+
+                       //statistic:
+                       usbvision->ComprBlockTypes[BlockType]++;
+
+                       Pos = ExtraPos;
+                       if (BlockType == 0) {
+                               if(RestPixel >= 24) {
+                                       Idx += 23;
+                                       RestPixel -= 24;
+                                       Integrator = Decompressed[Idx];
+                               } else {
+                                       Idx += RestPixel - 1;
+                                       RestPixel = 0;
+                               }
+                       } else {
+                               BlockCode = Compressed[Pos];
+                               Pos++;
+                               if (RestPixel >= 24) {
+                                       BlockLen  = 24;
+                               } else {
+                                       BlockLen = RestPixel;
+                               }
+                               RestPixel -= BlockLen;
+                               ExtraPos = Pos + (BlockLen / 4);
+                       }
+                       BlockTypeByte <<= 2;
+                       BlockTypeLen -= 1;
+               }
+               if (BlockLen > 0) {
+                       if ((BlockLen%4) == 0) {
+                               BlockByte = Compressed[Pos];
+                               Pos++;
+                       }
+                       if (BlockType == 1) { //inter Block
+                               Integrator = Decompressed[Idx];
+                       }
+                       switch (BlockByte & 0xC0) {
+                               case 0x03<<6:
+                                       Integrator += Compressed[ExtraPos];
+                                       ExtraPos++;
+                                       break;
+                               case 0x02<<6:
+                                       Integrator += BlockCode;
+                                       break;
+                               case 0x00:
+                                       Integrator -= BlockCode;
+                                       break;
+                       }
+                       Decompressed[Idx] = Integrator;
+                       BlockByte <<= 2;
+                       BlockLen -= 1;
+               }
+       }
+       *StartPos = ExtraPos;
+       *BlockTypeStartPos = BlockTypePos;
+       return Idx;
+}
+
+
+/*
+ * usbvision_parse_compress()
+ *
+ * Parse compressed frame from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ */
+static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
+                                          long *pcopylen)
+{
+#define USBVISION_STRIP_MAGIC          0x5A
+#define USBVISION_STRIP_LEN_MAX                400
+#define USBVISION_STRIP_HEADER_LEN     3
+
+       struct usbvision_frame *frame;
+       unsigned char *f,*u = NULL ,*v = NULL;
+       unsigned char StripData[USBVISION_STRIP_LEN_MAX];
+       unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN];
+       int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos;
+       int clipmask_index, bytes_per_pixel, rc;
+       int imageSize;
+       unsigned char rv, gv, bv;
+       static unsigned char *Y, *U, *V;
+
+       frame  = usbvision->curFrame;
+       imageSize = frame->frmwidth * frame->frmheight;
+       if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
+            (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) {       // this is a planar format
+               //... v4l2_linesize not used here.
+               f = frame->data + (frame->width * frame->curline);
+       } else
+               f = frame->data + (frame->v4l2_linesize * frame->curline);
+
+       if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers
+               // get base of u and b planes add halfoffset
+
+               u = frame->data
+                       + imageSize
+                       + (frame->frmwidth >>1) * frame->curline ;
+               v = u + (imageSize >>1 );
+
+       } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){
+
+               v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ;
+               u = v + (imageSize >>2) ;
+       }
+
+       if (frame->curline == 0) {
+               usbvision_adjust_compression(usbvision);
+       }
+
+       if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) {
+               return ParseState_Out;
+       }
+
+       //get strip header without changing the scratch_read_ptr
+       scratch_set_extra_ptr(usbvision, &StripPtr, 0);
+       scratch_get_extra(usbvision, &StripHeader[0], &StripPtr,
+                               USBVISION_STRIP_HEADER_LEN);
+
+       if (StripHeader[0] != USBVISION_STRIP_MAGIC) {
+               // wrong strip magic
+               usbvision->stripMagicErrors++;
+               return ParseState_NextFrame;
+       }
+
+       if (frame->curline != (int)StripHeader[2]) {
+               //line number missmatch error
+               usbvision->stripLineNumberErrors++;
+       }
+
+       StripLen = 2 * (unsigned int)StripHeader[1];
+       if (StripLen > USBVISION_STRIP_LEN_MAX) {
+               // strip overrun
+               // I think this never happens
+               usbvision_request_intra(usbvision);
+       }
+
+       if (scratch_len(usbvision) < StripLen) {
+               //there is not enough data for the strip
+               return ParseState_Out;
+       }
+
+       if (usbvision->IntraFrameBuffer) {
+               Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline;
+               U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2);
+               V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
+       }
+       else {
+               return ParseState_NextFrame;
+       }
+
+       bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+       clipmask_index = frame->curline * MAX_FRAME_WIDTH;
+
+       scratch_get(usbvision, StripData, StripLen);
+
+       IdxEnd = frame->frmwidth;
+       BlockTypePos = USBVISION_STRIP_HEADER_LEN;
+       StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2;
+       BlockPos = StartBlockPos;
+
+       usbvision->BlockPos = BlockPos;
+
+       if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) {
+               //return ParseState_Continue;
+       }
+       if (StripLen > usbvision->maxStripLen) {
+               usbvision->maxStripLen = StripLen;
+       }
+
+       if (frame->curline%2) {
+               if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
+               //return ParseState_Continue;
+               }
+       }
+       else {
+               if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
+                       //return ParseState_Continue;
+               }
+       }
+
+       if (BlockPos > usbvision->comprBlockPos) {
+               usbvision->comprBlockPos = BlockPos;
+       }
+       if (BlockPos > StripLen) {
+               usbvision->stripLenErrors++;
+       }
+
+       for (Idx = 0; Idx < IdxEnd; Idx++) {
+               if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                       *f++ = Y[Idx];
+                       *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2];
+               }
+               else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
+                       *f++ = Y[Idx];
+                       if ( Idx & 0x01)
+                               *u++ = U[Idx>>1] ;
+                       else
+                               *v++ = V[Idx>>1];
+               }
+               else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+                       *f++ = Y [Idx];
+                       if ( !((  Idx & 0x01  ) | (  frame->curline & 0x01  )) ){
+
+/*                              only need do this for 1 in 4 pixels */
+/*                              intraframe buffer is YUV420 format */
+
+                               *u++ = U[Idx >>1];
+                               *v++ = V[Idx >>1];
+                       }
+
+               }
+               else {
+                       YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv);
+                       switch (frame->v4l2_format.format) {
+                               case V4L2_PIX_FMT_GREY:
+                                       *f++ = Y[Idx];
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
+                                       *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+                                       break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
+                                       *f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       *f++ = bv;
+                                       *f++ = gv;
+                                       *f++ = rv;
+                                       f++;
+                                       break;
+                       }
+               }
+               clipmask_index++;
+       }
+       /* Deal with non-integer no. of bytes for YUV420P */
+       if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 )
+               *pcopylen += frame->v4l2_linesize;
+       else
+               *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1;
+
+       frame->curline += 1;
+
+       if (frame->curline >= frame->frmheight) {
+               return ParseState_NextFrame;
+       }
+       else {
+               return ParseState_Continue;
+       }
+
+}
+
+
+/*
+ * usbvision_parse_lines_420()
+ *
+ * Parse two lines from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ */
+static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision,
+                                          long *pcopylen)
+{
+       struct usbvision_frame *frame;
+       unsigned char *f_even = NULL, *f_odd = NULL;
+       unsigned int pixel_per_line, block;
+       int pixel, block_split;
+       int y_ptr, u_ptr, v_ptr, y_odd_offset;
+       const int   y_block_size = 128;
+       const int  uv_block_size = 64;
+       const int sub_block_size = 32;
+       const int y_step[] = { 0, 0, 0, 2 },  y_step_size = 4;
+       const int uv_step[]= { 0, 0, 0, 4 }, uv_step_size = 4;
+       unsigned char y[2], u, v;       /* YUV components */
+       int y_, u_, v_, vb, uvg, ur;
+       int r_, g_, b_;                 /* RGB components */
+       unsigned char g;
+       int clipmask_even_index, clipmask_odd_index, bytes_per_pixel;
+       int clipmask_add, stretch_bytes;
+
+       frame  = usbvision->curFrame;
+       f_even = frame->data + (frame->v4l2_linesize * frame->curline);
+       f_odd  = f_even + frame->v4l2_linesize * usbvision->stretch_height;
+
+       /* Make sure there's enough data for the entire line */
+       /* In this mode usbvision transfer 3 bytes for every 2 pixels */
+       /* I need two lines to decode the color */
+       bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
+       stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
+       clipmask_even_index = frame->curline * MAX_FRAME_WIDTH;
+       clipmask_odd_index  = clipmask_even_index + MAX_FRAME_WIDTH;
+       clipmask_add = usbvision->stretch_width;
+       pixel_per_line = frame->isocHeader.frameWidth;
+
+       if (scratch_len(usbvision) < (int)pixel_per_line * 3) {
+               //printk(KERN_DEBUG "out of data, need %d\n", len);
+               return ParseState_Out;
+       }
+
+       if ((frame->curline + 1) >= frame->frmheight) {
+               return ParseState_NextFrame;
+       }
+
+       block_split = (pixel_per_line%y_block_size) ? 1 : 0;    //are some blocks splitted into different lines?
+
+       y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size)
+                       + block_split * uv_block_size;
+
+       scratch_set_extra_ptr(usbvision, &y_ptr, y_odd_offset);
+       scratch_set_extra_ptr(usbvision, &u_ptr, y_block_size);
+       scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset
+                       + (4 - block_split) * sub_block_size);
+
+       for (block = 0; block < (pixel_per_line / sub_block_size);
+            block++) {
+
+
+               for (pixel = 0; pixel < sub_block_size; pixel +=2) {
+                       scratch_get(usbvision, &y[0], 2);
+                       scratch_get_extra(usbvision, &u, &u_ptr, 1);
+                       scratch_get_extra(usbvision, &v, &v_ptr, 1);
+
+                       //I don't use the YUV_TO_RGB macro for better performance
+                       v_ = v - 128;
+                       u_ = u - 128;
+                       vb =              132252 * v_;
+                       uvg= -53281 * u_ - 25625 * v_;
+                       ur = 104595 * u_;
+
+                       if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                               *f_even++ = y[0];
+                               *f_even++ = v;
+                       }
+                       else {
+                               y_ = 76284 * (y[0] - 16);
+
+                               b_ = (y_ + vb) >> 16;
+                               g_ = (y_ + uvg)>> 16;
+                               r_ = (y_ + ur) >> 16;
+
+                               switch (frame->v4l2_format.format) {
+                                       case V4L2_PIX_FMT_RGB565:
+                                               g = LIMIT_RGB(g_);
+                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+                                               *f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+                                               break;
+                                       case V4L2_PIX_FMT_RGB24:
+                                               *f_even++ = LIMIT_RGB(b_);
+                                               *f_even++ = LIMIT_RGB(g_);
+                                               *f_even++ = LIMIT_RGB(r_);
+                                               break;
+                                       case V4L2_PIX_FMT_RGB32:
+                                               *f_even++ = LIMIT_RGB(b_);
+                                               *f_even++ = LIMIT_RGB(g_);
+                                               *f_even++ = LIMIT_RGB(r_);
+                                               f_even++;
+                                               break;
+                                       case V4L2_PIX_FMT_RGB555:
+                                               g = LIMIT_RGB(g_);
+                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+                                               *f_even++ = (0x03 & (          g   >> 6)) |
+                                                           (0x7C & (LIMIT_RGB(r_) >> 1));
+                                               break;
+                               }
+                       }
+                       clipmask_even_index += clipmask_add;
+                       f_even += stretch_bytes;
+
+                       if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                               *f_even++ = y[1];
+                               *f_even++ = u;
+                       }
+                       else {
+                               y_ = 76284 * (y[1] - 16);
+
+                               b_ = (y_ + vb) >> 16;
+                               g_ = (y_ + uvg)>> 16;
+                               r_ = (y_ + ur) >> 16;
+
+                               switch (frame->v4l2_format.format) {
+                                       case V4L2_PIX_FMT_RGB565:
+                                               g = LIMIT_RGB(g_);
+                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+                                               *f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+                                               break;
+                                       case V4L2_PIX_FMT_RGB24:
+                                               *f_even++ = LIMIT_RGB(b_);
+                                               *f_even++ = LIMIT_RGB(g_);
+                                               *f_even++ = LIMIT_RGB(r_);
+                                               break;
+                                       case V4L2_PIX_FMT_RGB32:
+                                               *f_even++ = LIMIT_RGB(b_);
+                                               *f_even++ = LIMIT_RGB(g_);
+                                               *f_even++ = LIMIT_RGB(r_);
+                                               f_even++;
+                                               break;
+                                       case V4L2_PIX_FMT_RGB555:
+                                               g = LIMIT_RGB(g_);
+                                               *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+                                               *f_even++ = (0x03 & (          g   >> 6)) |
+                                                           (0x7C & (LIMIT_RGB(r_) >> 1));
+                                               break;
+                               }
+                       }
+                       clipmask_even_index += clipmask_add;
+                       f_even += stretch_bytes;
+
+                       scratch_get_extra(usbvision, &y[0], &y_ptr, 2);
+
+                       if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                               *f_odd++ = y[0];
+                               *f_odd++ = v;
+                       }
+                       else {
+                               y_ = 76284 * (y[0] - 16);
+
+                               b_ = (y_ + vb) >> 16;
+                               g_ = (y_ + uvg)>> 16;
+                               r_ = (y_ + ur) >> 16;
+
+                               switch (frame->v4l2_format.format) {
+                                       case V4L2_PIX_FMT_RGB565:
+                                               g = LIMIT_RGB(g_);
+                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+                                               *f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+                                               break;
+                                       case V4L2_PIX_FMT_RGB24:
+                                               *f_odd++ = LIMIT_RGB(b_);
+                                               *f_odd++ = LIMIT_RGB(g_);
+                                               *f_odd++ = LIMIT_RGB(r_);
+                                               break;
+                                       case V4L2_PIX_FMT_RGB32:
+                                               *f_odd++ = LIMIT_RGB(b_);
+                                               *f_odd++ = LIMIT_RGB(g_);
+                                               *f_odd++ = LIMIT_RGB(r_);
+                                               f_odd++;
+                                               break;
+                                       case V4L2_PIX_FMT_RGB555:
+                                               g = LIMIT_RGB(g_);
+                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+                                               *f_odd++ = (0x03 & (          g   >> 6)) |
+                                                          (0x7C & (LIMIT_RGB(r_) >> 1));
+                                               break;
+                               }
+                       }
+                       clipmask_odd_index += clipmask_add;
+                       f_odd += stretch_bytes;
+
+                       if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+                               *f_odd++ = y[1];
+                               *f_odd++ = u;
+                       }
+                       else {
+                               y_ = 76284 * (y[1] - 16);
+
+                               b_ = (y_ + vb) >> 16;
+                               g_ = (y_ + uvg)>> 16;
+                               r_ = (y_ + ur) >> 16;
+
+                               switch (frame->v4l2_format.format) {
+                                       case V4L2_PIX_FMT_RGB565:
+                                               g = LIMIT_RGB(g_);
+                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
+                                               *f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
+                                               break;
+                                       case V4L2_PIX_FMT_RGB24:
+                                               *f_odd++ = LIMIT_RGB(b_);
+                                               *f_odd++ = LIMIT_RGB(g_);
+                                               *f_odd++ = LIMIT_RGB(r_);
+                                               break;
+                                       case V4L2_PIX_FMT_RGB32:
+                                               *f_odd++ = LIMIT_RGB(b_);
+                                               *f_odd++ = LIMIT_RGB(g_);
+                                               *f_odd++ = LIMIT_RGB(r_);
+                                               f_odd++;
+                                               break;
+                                       case V4L2_PIX_FMT_RGB555:
+                                               g = LIMIT_RGB(g_);
+                                               *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
+                                               *f_odd++ = (0x03 & (          g   >> 6)) |
+                                                          (0x7C & (LIMIT_RGB(r_) >> 1));
+                                               break;
+                               }
+                       }
+                       clipmask_odd_index += clipmask_add;
+                       f_odd += stretch_bytes;
+               }
+
+               scratch_rm_old(usbvision,y_step[block % y_step_size] * sub_block_size);
+               scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size]
+                               * sub_block_size);
+               scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size]
+                               * sub_block_size);
+               scratch_inc_extra_ptr(&v_ptr, uv_step[(block + 2 * block_split) % uv_step_size]
+                               * sub_block_size);
+       }
+
+       scratch_rm_old(usbvision, pixel_per_line * 3 / 2
+                       + block_split * sub_block_size);
+
+       frame->curline += 2 * usbvision->stretch_height;
+       *pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height;
+
+       if (frame->curline >= frame->frmheight)
+               return ParseState_NextFrame;
+       else
+               return ParseState_Continue;
+}
+
+/*
+ * usbvision_parse_data()
+ *
+ * Generic routine to parse the scratch buffer. It employs either
+ * usbvision_find_header() or usbvision_parse_lines() to do most
+ * of work.
+ *
+ */
+static void usbvision_parse_data(struct usb_usbvision *usbvision)
+{
+       struct usbvision_frame *frame;
+       enum ParseState newstate;
+       long copylen = 0;
+       unsigned long lock_flags;
+
+       frame = usbvision->curFrame;
+
+       PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision));
+
+       while (1) {
+
+               newstate = ParseState_Out;
+               if (scratch_len(usbvision)) {
+                       if (frame->scanstate == ScanState_Scanning) {
+                               newstate = usbvision_find_header(usbvision);
+                       }
+                       else if (frame->scanstate == ScanState_Lines) {
+                               if (usbvision->isocMode == ISOC_MODE_YUV420) {
+                                       newstate = usbvision_parse_lines_420(usbvision, &copylen);
+                               }
+                               else if (usbvision->isocMode == ISOC_MODE_YUV422) {
+                                       newstate = usbvision_parse_lines_422(usbvision, &copylen);
+                               }
+                               else if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+                                       newstate = usbvision_parse_compress(usbvision, &copylen);
+                               }
+
+                       }
+               }
+               if (newstate == ParseState_Continue) {
+                       continue;
+               }
+               else if ((newstate == ParseState_NextFrame) || (newstate == ParseState_Out)) {
+                       break;
+               }
+               else {
+                       return; /* ParseState_EndParse */
+               }
+       }
+
+       if (newstate == ParseState_NextFrame) {
+               frame->grabstate = FrameState_Done;
+               do_gettimeofday(&(frame->timestamp));
+               frame->sequence = usbvision->frame_num;
+
+               spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+               list_move_tail(&(frame->frame), &usbvision->outqueue);
+               usbvision->curFrame = NULL;
+               spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+               usbvision->frame_num++;
+
+               /* This will cause the process to request another frame. */
+               if (waitqueue_active(&usbvision->wait_frame)) {
+                       PDEBUG(DBG_PARSE, "Wake up !");
+                       wake_up_interruptible(&usbvision->wait_frame);
+               }
+       }
+       else
+               frame->grabstate = FrameState_Grabbing;
+
+
+       /* Update the frame's uncompressed length. */
+       frame->scanlength += copylen;
+}
+
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
+                                         struct urb *urb)
+{
+       unsigned char *packet_data;
+       int i, totlen = 0;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               int packet_len = urb->iso_frame_desc[i].actual_length;
+               int packet_stat = urb->iso_frame_desc[i].status;
+
+               packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (packet_stat) {      // packet_stat != 0 ?????????????
+                       PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat);
+                       usbvision->isocErrCount++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (packet_len < 0) {
+                       PDEBUG(DBG_ISOC, "error packet [%d]", i);
+                       usbvision->isocSkipCount++;
+                       continue;
+               }
+               else if (packet_len == 0) {     /* Frame end ????? */
+                       PDEBUG(DBG_ISOC, "null packet [%d]", i);
+                       usbvision->isocstate=IsocState_NoFrame;
+                       usbvision->isocSkipCount++;
+                       continue;
+               }
+               else if (packet_len > usbvision->isocPacketSize) {
+                       PDEBUG(DBG_ISOC, "packet[%d] > isocPacketSize", i);
+                       usbvision->isocSkipCount++;
+                       continue;
+               }
+
+               PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len);
+
+               if (usbvision->isocstate==IsocState_NoFrame) { //new frame begins
+                       usbvision->isocstate=IsocState_InFrame;
+                       scratch_mark_header(usbvision);
+                       usbvision_measure_bandwidth(usbvision);
+                       PDEBUG(DBG_ISOC, "packet with header");
+               }
+
+               /*
+                * If usbvision continues to feed us with data but there is no
+                * consumption (if, for example, V4L client fell asleep) we
+                * may overflow the buffer. We have to move old data over to
+                * free room for new data. This is bad for old data. If we
+                * just drop new data then it's bad for new data... choose
+                * your favorite evil here.
+                */
+               if (scratch_free(usbvision) < packet_len) {
+
+                       usbvision->scratch_ovf_count++;
+                       PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d",
+                              scratch_len(usbvision), packet_len);
+                       scratch_rm_old(usbvision, packet_len - scratch_free(usbvision));
+               }
+
+               /* Now we know that there is enough room in scratch buffer */
+               scratch_put(usbvision, packet_data, packet_len);
+               totlen += packet_len;
+               usbvision->isocDataCount += packet_len;
+               usbvision->isocPacketCount++;
+       }
+#if ENABLE_HEXDUMP
+       if (totlen > 0) {
+               static int foo = 0;
+               if (foo < 1) {
+                       printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
+                       usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
+                       ++foo;
+               }
+       }
+#endif
+ return totlen;
+}
+
+static void usbvision_isocIrq(struct urb *urb)
+{
+       int errCode = 0;
+       int len;
+       struct usb_usbvision *usbvision = urb->context;
+       int i;
+       unsigned long startTime = jiffies;
+       struct usbvision_frame **f;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return;
+
+       f = &usbvision->curFrame;
+
+       /* Manage streaming interruption */
+       if (usbvision->streaming == Stream_Interrupt) {
+               usbvision->streaming = Stream_Idle;
+               if ((*f)) {
+                       (*f)->grabstate = FrameState_Ready;
+                       (*f)->scanstate = ScanState_Scanning;
+               }
+               PDEBUG(DBG_IRQ, "stream interrupted");
+               wake_up_interruptible(&usbvision->wait_stream);
+       }
+
+       /* Copy the data received into our scratch buffer */
+       len = usbvision_compress_isochronous(usbvision, urb);
+
+       usbvision->isocUrbCount++;
+       usbvision->urb_length = len;
+
+       if (usbvision->streaming == Stream_On) {
+
+               /* If we collected enough data let's parse! */
+               if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */
+                       /*If we don't have a frame we're current working on, complain */
+                       if(!list_empty(&(usbvision->inqueue))) {
+                               if (!(*f)) {
+                                       (*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame);
+                               }
+                               usbvision_parse_data(usbvision);
+                       }
+                       else {
+                               PDEBUG(DBG_IRQ, "received data, but no one needs it");
+                               scratch_reset(usbvision);
+                       }
+               }
+       }
+       else {
+               PDEBUG(DBG_IRQ, "received data, but no one needs it");
+               scratch_reset(usbvision);
+       }
+
+       usbvision->timeInIrq += jiffies - startTime;
+
+       for (i = 0; i < USBVISION_URB_FRAMES; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+
+       urb->status = 0;
+       urb->dev = usbvision->dev;
+       errCode = usb_submit_urb (urb, GFP_ATOMIC);
+
+       /* Disable this warning.  By design of the driver. */
+       //      if(errCode) {
+       //              err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode);
+       //      }
+
+       return;
+}
+
+/*************************************/
+/* Low level usbvision access functions */
+/*************************************/
+
+/*
+ * usbvision_read_reg()
+ *
+ * return  < 0 -> Error
+ *        >= 0 -> Data
+ */
+
+int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
+{
+       int errCode = 0;
+       unsigned char buffer[1];
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return -1;
+
+       errCode = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
+                               USBVISION_OP_CODE,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                               0, (__u16) reg, buffer, 1, HZ);
+
+       if (errCode < 0) {
+               err("%s: failed: error %d", __FUNCTION__, errCode);
+               return errCode;
+       }
+       return buffer[0];
+}
+
+/*
+ * usbvision_write_reg()
+ *
+ * return 1 -> Reg written
+ *        0 -> usbvision is not yet ready
+ *       -1 -> Something went wrong
+ */
+
+int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
+                           unsigned char value)
+{
+       int errCode = 0;
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                               USBVISION_OP_CODE,
+                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                               USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
+
+       if (errCode < 0) {
+               err("%s: failed: error %d", __FUNCTION__, errCode);
+       }
+       return errCode;
+}
+
+
+static void usbvision_ctrlUrb_complete(struct urb *urb)
+{
+       struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context;
+
+       PDEBUG(DBG_IRQ, "");
+       usbvision->ctrlUrbBusy = 0;
+       if (waitqueue_active(&usbvision->ctrlUrb_wq)) {
+               wake_up_interruptible(&usbvision->ctrlUrb_wq);
+       }
+}
+
+
+static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
+                                                                       unsigned char *data, int len)
+{
+       int errCode = 0;
+
+       PDEBUG(DBG_IRQ, "");
+       if (len > 8) {
+               return -EFAULT;
+       }
+//     down(&usbvision->ctrlUrbLock);
+       if (usbvision->ctrlUrbBusy) {
+//             up(&usbvision->ctrlUrbLock);
+               return -EBUSY;
+       }
+       usbvision->ctrlUrbBusy = 1;
+//     up(&usbvision->ctrlUrbLock);
+
+       usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+       usbvision->ctrlUrbSetup.bRequest     = USBVISION_OP_CODE;
+       usbvision->ctrlUrbSetup.wValue       = 0;
+       usbvision->ctrlUrbSetup.wIndex       = cpu_to_le16(address);
+       usbvision->ctrlUrbSetup.wLength      = cpu_to_le16(len);
+       usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev,
+                                                       usb_sndctrlpipe(usbvision->dev, 1),
+                                                       (unsigned char *)&usbvision->ctrlUrbSetup,
+                                                       (void *)usbvision->ctrlUrbBuffer, len,
+                                                       usbvision_ctrlUrb_complete,
+                                                       (void *)usbvision);
+
+       memcpy(usbvision->ctrlUrbBuffer, data, len);
+
+       errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC);
+       if (errCode < 0) {
+               // error in usb_submit_urb()
+               usbvision->ctrlUrbBusy = 0;
+       }
+       PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, errCode);
+       return errCode;
+}
+
+
+static int usbvision_init_compression(struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+
+       usbvision->lastIsocFrameNum = -1;
+       usbvision->isocDataCount = 0;
+       usbvision->isocPacketCount = 0;
+       usbvision->isocSkipCount = 0;
+       usbvision->comprLevel = 50;
+       usbvision->lastComprLevel = -1;
+       usbvision->isocUrbCount = 0;
+       usbvision->requestIntra = 1;
+       usbvision->isocMeasureBandwidthCount = 0;
+
+       return errCode;
+}
+
+/* this function measures the used bandwidth since last call
+ * return:    0 : no error
+ * sets usedBandwidth to 1-100 : 1-100% of full bandwidth resp. to isocPacketSize
+ */
+static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+
+       if (usbvision->isocMeasureBandwidthCount < 2) { // this gives an average bandwidth of 3 frames
+               usbvision->isocMeasureBandwidthCount++;
+               return errCode;
+       }
+       if ((usbvision->isocPacketSize > 0) && (usbvision->isocPacketCount > 0)) {
+               usbvision->usedBandwidth = usbvision->isocDataCount /
+                                       (usbvision->isocPacketCount + usbvision->isocSkipCount) *
+                                       100 / usbvision->isocPacketSize;
+       }
+       usbvision->isocMeasureBandwidthCount = 0;
+       usbvision->isocDataCount = 0;
+       usbvision->isocPacketCount = 0;
+       usbvision->isocSkipCount = 0;
+       return errCode;
+}
+
+static int usbvision_adjust_compression (struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+       unsigned char buffer[6];
+
+       PDEBUG(DBG_IRQ, "");
+       if ((adjustCompression) && (usbvision->usedBandwidth > 0)) {
+               usbvision->comprLevel += (usbvision->usedBandwidth - 90) / 2;
+               RESTRICT_TO_RANGE(usbvision->comprLevel, 0, 100);
+               if (usbvision->comprLevel != usbvision->lastComprLevel) {
+                       int distorsion;
+                       if (usbvision->bridgeType == BRIDGE_NT1004 || usbvision->bridgeType == BRIDGE_NT1005) {
+                               buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100);      // PCM Threshold 1
+                               buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100);       // PCM Threshold 2
+                               distorsion = 7 + 248 * usbvision->comprLevel / 100;
+                               buffer[2] = (unsigned char)(distorsion & 0xFF);                         // Average distorsion Threshold (inter)
+                               buffer[3] = (unsigned char)(distorsion & 0xFF);                         // Average distorsion Threshold (intra)
+                               distorsion = 1 + 42 * usbvision->comprLevel / 100;
+                               buffer[4] = (unsigned char)(distorsion & 0xFF);                         // Maximum distorsion Threshold (inter)
+                               buffer[5] = (unsigned char)(distorsion & 0xFF);                         // Maximum distorsion Threshold (intra)
+                       }
+                       else { //BRIDGE_NT1003
+                               buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100);      // PCM threshold 1
+                               buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100);       // PCM threshold 2
+                               distorsion = 2 + 253 * usbvision->comprLevel / 100;
+                               buffer[2] = (unsigned char)(distorsion & 0xFF);                         // distorsion threshold bit0-7
+                               buffer[3] = 0;  //(unsigned char)((distorsion >> 8) & 0x0F);            // distorsion threshold bit 8-11
+                               distorsion = 0 + 43 * usbvision->comprLevel / 100;
+                               buffer[4] = (unsigned char)(distorsion & 0xFF);                         // maximum distorsion bit0-7
+                               buffer[5] = 0; //(unsigned char)((distorsion >> 8) & 0x01);             // maximum distorsion bit 8
+                       }
+                       errCode = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
+                       if (errCode == 0){
+                               PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0],
+                                                               buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
+                               usbvision->lastComprLevel = usbvision->comprLevel;
+                       }
+               }
+       }
+       return errCode;
+}
+
+static int usbvision_request_intra (struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+       unsigned char buffer[1];
+
+       PDEBUG(DBG_IRQ, "");
+       usbvision->requestIntra = 1;
+       buffer[0] = 1;
+       usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
+       return errCode;
+}
+
+static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+       unsigned char buffer[1];
+
+       PDEBUG(DBG_IRQ, "");
+       usbvision->requestIntra = 0;
+       buffer[0] = 0;
+       usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
+       return errCode;
+}
+
+/*******************************
+ * usbvision utility functions
+ *******************************/
+
+int usbvision_power_off(struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+
+       PDEBUG(DBG_FUNC, "");
+
+       errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+       if (errCode == 1) {
+               usbvision->power = 0;
+       }
+       PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode!=1)?"ERROR":"power is off", errCode);
+       return errCode;
+}
+
+/*
+ * usbvision_set_video_format()
+ *
+ */
+static int usbvision_set_video_format(struct usb_usbvision *usbvision, int format)
+{
+       static const char proc[] = "usbvision_set_video_format";
+       int rc;
+       unsigned char value[2];
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       PDEBUG(DBG_FUNC, "isocMode %#02x", format);
+
+       if ((format != ISOC_MODE_YUV422)
+           && (format != ISOC_MODE_YUV420)
+           && (format != ISOC_MODE_COMPRESS)) {
+               printk(KERN_ERR "usbvision: unknown video format %02x, using default YUV420",
+                      format);
+               format = ISOC_MODE_YUV420;
+       }
+       value[0] = 0x0A;  //TODO: See the effect of the filter
+       value[1] = format;
+       rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE,
+                            USB_DIR_OUT | USB_TYPE_VENDOR |
+                            USB_RECIP_ENDPOINT, 0,
+                            (__u16) USBVISION_FILT_CONT, value, 2, HZ);
+
+       if (rc < 0) {
+               printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - "
+                      "reconnect or reload driver.\n", proc, rc);
+       }
+       usbvision->isocMode = format;
+       return rc;
+}
+
+/*
+ * usbvision_set_output()
+ *
+ */
+
+int usbvision_set_output(struct usb_usbvision *usbvision, int width,
+                        int height)
+{
+       int errCode = 0;
+       int UsbWidth, UsbHeight;
+       unsigned int frameRate=0, frameDrop=0;
+       unsigned char value[4];
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+               return 0;
+       }
+
+       if (width > MAX_USB_WIDTH) {
+               UsbWidth = width / 2;
+               usbvision->stretch_width = 2;
+       }
+       else {
+               UsbWidth = width;
+               usbvision->stretch_width = 1;
+       }
+
+       if (height > MAX_USB_HEIGHT) {
+               UsbHeight = height / 2;
+               usbvision->stretch_height = 2;
+       }
+       else {
+               UsbHeight = height;
+               usbvision->stretch_height = 1;
+       }
+
+       RESTRICT_TO_RANGE(UsbWidth, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
+       UsbWidth &= ~(MIN_FRAME_WIDTH-1);
+       RESTRICT_TO_RANGE(UsbHeight, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
+       UsbHeight &= ~(1);
+
+       PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d",
+                                               UsbWidth, UsbHeight, width, height,
+                                               usbvision->stretch_width, usbvision->stretch_height);
+
+       /* I'll not rewrite the same values */
+       if ((UsbWidth != usbvision->curwidth) || (UsbHeight != usbvision->curheight)) {
+               value[0] = UsbWidth & 0xff;             //LSB
+               value[1] = (UsbWidth >> 8) & 0x03;      //MSB
+               value[2] = UsbHeight & 0xff;            //LSB
+               value[3] = (UsbHeight >> 8) & 0x03;     //MSB
+
+               errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE,
+                            USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                                0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
+
+               if (errCode < 0) {
+                       err("%s failed: error %d", __FUNCTION__, errCode);
+                       return errCode;
+               }
+               usbvision->curwidth = usbvision->stretch_width * UsbWidth;
+               usbvision->curheight = usbvision->stretch_height * UsbHeight;
+       }
+
+       if (usbvision->isocMode == ISOC_MODE_YUV422) {
+               frameRate = (usbvision->isocPacketSize * 1000) / (UsbWidth * UsbHeight * 2);
+       }
+       else if (usbvision->isocMode == ISOC_MODE_YUV420) {
+               frameRate = (usbvision->isocPacketSize * 1000) / ((UsbWidth * UsbHeight * 12) / 8);
+       }
+       else {
+               frameRate = FRAMERATE_MAX;
+       }
+
+       if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+               frameDrop = frameRate * 32 / 25 - 1;
+       }
+       else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+               frameDrop = frameRate * 32 / 30 - 1;
+       }
+
+       RESTRICT_TO_RANGE(frameDrop, FRAMERATE_MIN, FRAMERATE_MAX);
+
+       PDEBUG(DBG_FUNC, "frameRate %d fps, frameDrop %d", frameRate, frameDrop);
+
+       frameDrop = FRAMERATE_MAX;      // We can allow the maximum here, because dropping is controlled
+
+       /* frameDrop = 7; => framePhase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
+               => frameSkip = 4;
+               => frameRate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
+
+          frameDrop = 9; => framePhase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
+           => frameSkip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
+               => frameRate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
+       */
+       errCode = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frameDrop);
+       return errCode;
+}
+
+
+/*
+ * usbvision_frames_alloc
+ * allocate the maximum frames this driver can manage
+ */
+int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+{
+       int i;
+
+       /* Allocate memory for the frame buffers */
+       usbvision->max_frame_size = MAX_FRAME_SIZE;
+       usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
+       usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+
+       if(usbvision->fbuf == NULL) {
+               err("%s: unable to allocate %d bytes for fbuf ",
+                   __FUNCTION__, usbvision->fbuf_size);
+               return -ENOMEM;
+       }
+       spin_lock_init(&usbvision->queue_lock);
+       init_waitqueue_head(&usbvision->wait_frame);
+       init_waitqueue_head(&usbvision->wait_stream);
+
+       /* Allocate all buffers */
+       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+               usbvision->frame[i].index = i;
+               usbvision->frame[i].grabstate = FrameState_Unused;
+               usbvision->frame[i].data = usbvision->fbuf +
+                       i * usbvision->max_frame_size;
+               /*
+                * Set default sizes for read operation.
+                */
+               usbvision->stretch_width = 1;
+               usbvision->stretch_height = 1;
+               usbvision->frame[i].width = usbvision->curwidth;
+               usbvision->frame[i].height = usbvision->curheight;
+               usbvision->frame[i].bytes_read = 0;
+       }
+       return 0;
+}
+
+/*
+ * usbvision_frames_free
+ * frees memory allocated for the frames
+ */
+void usbvision_frames_free(struct usb_usbvision *usbvision)
+{
+       /* Have to free all that memory */
+       if (usbvision->fbuf != NULL) {
+               usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
+               usbvision->fbuf = NULL;
+       }
+}
+/*
+ * usbvision_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+void usbvision_empty_framequeues(struct usb_usbvision *usbvision)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&(usbvision->inqueue));
+       INIT_LIST_HEAD(&(usbvision->outqueue));
+
+       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+               usbvision->frame[i].grabstate = FrameState_Unused;
+               usbvision->frame[i].bytes_read = 0;
+       }
+}
+
+/*
+ * usbvision_stream_interrupt()
+ * stops streaming
+ */
+int usbvision_stream_interrupt(struct usb_usbvision *usbvision)
+{
+       int ret = 0;
+
+       /* stop reading from the device */
+
+       usbvision->streaming = Stream_Interrupt;
+       ret = wait_event_timeout(usbvision->wait_stream,
+                                (usbvision->streaming == Stream_Idle),
+                                msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES));
+       return ret;
+}
+
+/*
+ * usbvision_set_compress_params()
+ *
+ */
+
+static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
+{
+       static const char proc[] = "usbvision_set_compresion_params: ";
+       int rc;
+       unsigned char value[6];
+
+       value[0] = 0x0F;    // Intra-Compression cycle
+       value[1] = 0x01;    // Reg.45 one line per strip
+       value[2] = 0x00;    // Reg.46 Force intra mode on all new frames
+       value[3] = 0x00;    // Reg.47 FORCE_UP <- 0 normal operation (not force)
+       value[4] = 0xA2;    // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode.
+       value[5] = 0x00;    // Reg.49 DVI_YUV This has nothing to do with compression
+
+       //catched values for NT1004
+       // value[0] = 0xFF; // Never apply intra mode automatically
+       // value[1] = 0xF1; // Use full frame height for virtual strip width; One line per strip
+       // value[2] = 0x01; // Force intra mode on all new frames
+       // value[3] = 0x00; // Strip size 400 Bytes; do not force up
+       // value[4] = 0xA2; //
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE,
+                            USB_DIR_OUT | USB_TYPE_VENDOR |
+                            USB_RECIP_ENDPOINT, 0,
+                            (__u16) USBVISION_INTRA_CYC, value, 5, HZ);
+
+       if (rc < 0) {
+               printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+                      "reconnect or reload driver.\n", proc, rc);
+               return rc;
+       }
+
+       if (usbvision->bridgeType == BRIDGE_NT1004) {
+               value[0] =  20; // PCM Threshold 1
+               value[1] =  12; // PCM Threshold 2
+               value[2] = 255; // Distorsion Threshold inter
+               value[3] = 255; // Distorsion Threshold intra
+               value[4] =  43; // Max Distorsion inter
+               value[5] =  43; // Max Distorsion intra
+       }
+       else {
+               value[0] =  20; // PCM Threshold 1
+               value[1] =  12; // PCM Threshold 2
+               value[2] = 255; // Distorsion Threshold d7-d0
+               value[3] =   0; // Distorsion Threshold d11-d8
+               value[4] =  43; // Max Distorsion d7-d0
+               value[5] =   0; // Max Distorsion d8
+       }
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE,
+                            USB_DIR_OUT | USB_TYPE_VENDOR |
+                            USB_RECIP_ENDPOINT, 0,
+                            (__u16) USBVISION_PCM_THR1, value, 6, HZ);
+
+       if (rc < 0) {
+               printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+                      "reconnect or reload driver.\n", proc, rc);
+               return rc;
+       }
+
+
+       return rc;
+}
+
+
+/*
+ * usbvision_set_input()
+ *
+ * Set the input (saa711x, ...) size x y and other misc input params
+ * I've no idea if this parameters are right
+ *
+ */
+int usbvision_set_input(struct usb_usbvision *usbvision)
+{
+       static const char proc[] = "usbvision_set_input: ";
+       int rc;
+       unsigned char value[8];
+       unsigned char dvi_yuv_value;
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       /* Set input format expected from decoder*/
+       if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) {
+               value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff;
+       } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+               /* SAA7113 uses 8 bit output */
+               value[0] = USBVISION_8_422_SYNC;
+       } else {
+               /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 usin sync pulses
+                * as that is how saa7111 is configured */
+               value[0] = USBVISION_16_422_SYNC;
+               /* | USBVISION_VSNC_POL | USBVISION_VCLK_POL);*/
+       }
+
+       rc = usbvision_write_reg(usbvision, USBVISION_VIN_REG1, value[0]);
+       if (rc < 0) {
+               printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+                      "reconnect or reload driver.\n", proc, rc);
+               return rc;
+       }
+
+
+       if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+               value[0] = 0xC0;
+               value[1] = 0x02;        //0x02C0 -> 704 Input video line length
+               value[2] = 0x20;
+               value[3] = 0x01;        //0x0120 -> 288 Input video n. of lines
+               value[4] = 0x60;
+               value[5] = 0x00;        //0x0060 -> 96 Input video h offset
+               value[6] = 0x16;
+               value[7] = 0x00;        //0x0016 -> 22 Input video v offset
+       } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+               value[0] = 0xC0;
+               value[1] = 0x02;        //0x02C0 -> 704 Input video line length
+               value[2] = 0x20;
+               value[3] = 0x01;        //0x0120 -> 288 Input video n. of lines
+               value[4] = 0x01;
+               value[5] = 0x00;        //0x0001 -> 01 Input video h offset
+               value[6] = 0x01;
+               value[7] = 0x00;        //0x0001 -> 01 Input video v offset
+       } else {        /* V4L2_STD_NTSC */
+               value[0] = 0xD0;
+               value[1] = 0x02;        //0x02D0 -> 720 Input video line length
+               value[2] = 0xF0;
+               value[3] = 0x00;        //0x00F0 -> 240 Input video number of lines
+               value[4] = 0x50;
+               value[5] = 0x00;        //0x0050 -> 80 Input video h offset
+               value[6] = 0x10;
+               value[7] = 0x00;        //0x0010 -> 16 Input video v offset
+       }
+
+       if (usbvision_device_data[usbvision->DevModel].X_Offset >= 0) {
+               value[4]=usbvision_device_data[usbvision->DevModel].X_Offset & 0xff;
+               value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
+       }
+
+       if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
+               value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
+               value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
+       }
+
+       rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE, /* USBVISION specific code */
+                            USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
+                            (__u16) USBVISION_LXSIZE_I, value, 8, HZ);
+       if (rc < 0) {
+               printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
+                      "reconnect or reload driver.\n", proc, rc);
+               return rc;
+       }
+
+
+       dvi_yuv_value = 0x00;   /* U comes after V, Ya comes after U/V, Yb comes after Yb */
+
+       if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){
+               dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff;
+       }
+       else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+       /* This changes as the fine sync control changes. Further investigation necessary */
+               dvi_yuv_value = 0x06;
+       }
+
+       return (usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value));
+}
+
+
+/*
+ * usbvision_set_dram_settings()
+ *
+ * Set the buffer address needed by the usbvision dram to operate
+ * This values has been taken with usbsnoop.
+ *
+ */
+
+static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
+{
+       int rc;
+       unsigned char value[8];
+
+       if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+               value[0] = 0x42;
+               value[1] = 0x71;
+               value[2] = 0xff;
+               value[3] = 0x00;
+               value[4] = 0x98;
+               value[5] = 0xe0;
+               value[6] = 0x71;
+               value[7] = 0xff;
+               // UR:  0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte)
+               // FDL: 0x00000-0x0E099 =  57498 Words
+               // VDW: 0x0E3FF-0x3FFFF
+       }
+       else {
+               value[0] = 0x42;
+               value[1] = 0x00;
+               value[2] = 0xff;
+               value[3] = 0x00;
+               value[4] = 0x00;
+               value[5] = 0x00;
+               value[6] = 0x00;
+               value[7] = 0xff;
+       }
+       /* These are the values of the address of the video buffer,
+        * they have to be loaded into the USBVISION_DRM_PRM1-8
+        *
+        * Start address of video output buffer for read:       drm_prm1-2 -> 0x00000
+        * End address of video output buffer for read:         drm_prm1-3 -> 0x1ffff
+        * Start address of video frame delay buffer:           drm_prm1-4 -> 0x20000
+        *    Only used in compressed mode
+        * End address of video frame delay buffer:             drm_prm1-5-6 -> 0x3ffff
+        *    Only used in compressed mode
+        * Start address of video output buffer for write:      drm_prm1-7 -> 0x00000
+        * End address of video output buffer for write:        drm_prm1-8 -> 0x1ffff
+        */
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return 0;
+
+       rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+                            USBVISION_OP_CODE, /* USBVISION specific code */
+                            USB_DIR_OUT | USB_TYPE_VENDOR |
+                            USB_RECIP_ENDPOINT, 0,
+                            (__u16) USBVISION_DRM_PRM1, value, 8, HZ);
+
+       if (rc < 0) {
+               err("%sERROR=%d", __FUNCTION__, rc);
+               return rc;
+       }
+
+       /* Restart the video buffer logic */
+       if ((rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
+                                  USBVISION_RES_FDL | USBVISION_RES_VDW)) < 0)
+               return rc;
+       rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00);
+
+       return rc;
+}
+
+/*
+ * ()
+ *
+ * Power on the device, enables suspend-resume logic
+ * &  reset the isoc End-Point
+ *
+ */
+
+int usbvision_power_on(struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+
+       PDEBUG(DBG_FUNC, "");
+
+       usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+       usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+                        USBVISION_SSPND_EN | USBVISION_RES2);
+       usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+                        USBVISION_SSPND_EN | USBVISION_PWR_VID);
+       errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+                                               USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
+       if (errCode == 1) {
+               usbvision->power = 1;
+       }
+       PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode<0)?"ERROR":"power is on", errCode);
+       return errCode;
+}
+
+
+/*
+ * usbvision timer stuff
+ */
+
+// to call usbvision_power_off from task queue
+static void call_usbvision_power_off(struct work_struct *work)
+{
+       struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
+
+       PDEBUG(DBG_FUNC, "");
+       down_interruptible(&usbvision->lock);
+       if(usbvision->user == 0) {
+               usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+
+               usbvision_power_off(usbvision);
+               usbvision->initialized = 0;
+       }
+       up(&usbvision->lock);
+}
+
+static void usbvision_powerOffTimer(unsigned long data)
+{
+       struct usb_usbvision *usbvision = (void *) data;
+
+       PDEBUG(DBG_FUNC, "");
+       del_timer(&usbvision->powerOffTimer);
+       INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
+       (void) schedule_work(&usbvision->powerOffWork);
+
+}
+
+void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
+{
+       init_timer(&usbvision->powerOffTimer);
+       usbvision->powerOffTimer.data = (long) usbvision;
+       usbvision->powerOffTimer.function = usbvision_powerOffTimer;
+}
+
+void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision)
+{
+       mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME);
+}
+
+void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
+{
+       if (timer_pending(&usbvision->powerOffTimer)) {
+               del_timer(&usbvision->powerOffTimer);
+       }
+}
+
+/*
+ * usbvision_begin_streaming()
+ * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no
+ * idea about the rest
+ */
+int usbvision_begin_streaming(struct usb_usbvision *usbvision)
+{
+       int errCode = 0;
+
+       if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+               usbvision_init_compression(usbvision);
+       }
+       errCode = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, USBVISION_NOHVALID |
+                                                                               usbvision->Vin_Reg2_Preset);
+       return errCode;
+}
+
+/*
+ * usbvision_restart_isoc()
+ * Not sure yet if touching here PWR_REG make loose the config
+ */
+
+int usbvision_restart_isoc(struct usb_usbvision *usbvision)
+{
+       int ret;
+
+       if (
+           (ret =
+            usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+                             USBVISION_SSPND_EN | USBVISION_PWR_VID)) < 0)
+               return ret;
+       if (
+           (ret =
+            usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+                             USBVISION_SSPND_EN | USBVISION_PWR_VID |
+                             USBVISION_RES2)) < 0)
+               return ret;
+       if (
+           (ret =
+            usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+                             USBVISION_KEEP_BLANK | USBVISION_NOHVALID |
+                                 usbvision->Vin_Reg2_Preset)) < 0) return ret;
+
+       /* TODO: schedule timeout */
+       while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) && 0x01) != 1);
+
+       return 0;
+}
+
+int usbvision_audio_off(struct usb_usbvision *usbvision)
+{
+       if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) {
+               printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n");
+               return -1;
+       }
+       usbvision->AudioMute = 0;
+       usbvision->AudioChannel = USBVISION_AUDIO_MUTE;
+       return 0;
+}
+
+int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel)
+{
+       if (!usbvision->AudioMute) {
+               if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) {
+                       printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n");
+                       return -1;
+               }
+       }
+       usbvision->AudioChannel = AudioChannel;
+       return 0;
+}
+
+int usbvision_setup(struct usb_usbvision *usbvision,int format)
+{
+       usbvision_set_video_format(usbvision, format);
+       usbvision_set_dram_settings(usbvision);
+       usbvision_set_compress_params(usbvision);
+       usbvision_set_input(usbvision);
+       usbvision_set_output(usbvision, MAX_USB_WIDTH, MAX_USB_HEIGHT);
+       usbvision_restart_isoc(usbvision);
+
+       /* cosas del PCM */
+       return USBVISION_IS_OPERATIONAL(usbvision);
+}
+
+
+int usbvision_sbuf_alloc(struct usb_usbvision *usbvision)
+{
+       int i, errCode = 0;
+       const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE;
+
+       /* Clean pointers so we know if we allocated something */
+       for (i = 0; i < USBVISION_NUMSBUF; i++)
+               usbvision->sbuf[i].data = NULL;
+
+       for (i = 0; i < USBVISION_NUMSBUF; i++) {
+               usbvision->sbuf[i].data = kzalloc(sb_size, GFP_KERNEL);
+               if (usbvision->sbuf[i].data == NULL) {
+                       err("%s: unable to allocate %d bytes for sbuf", __FUNCTION__, sb_size);
+                       errCode = -ENOMEM;
+                       break;
+               }
+       }
+       return errCode;
+}
+
+
+void usbvision_sbuf_free(struct usb_usbvision *usbvision)
+{
+       int i;
+
+       for (i = 0; i < USBVISION_NUMSBUF; i++) {
+               if (usbvision->sbuf[i].data != NULL) {
+                       kfree(usbvision->sbuf[i].data);
+                       usbvision->sbuf[i].data = NULL;
+               }
+       }
+}
+
+/*
+ * usbvision_init_isoc()
+ *
+ */
+int usbvision_init_isoc(struct usb_usbvision *usbvision)
+{
+       struct usb_device *dev = usbvision->dev;
+       int bufIdx, errCode, regValue;
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return -EFAULT;
+
+       usbvision->curFrame = NULL;
+       scratch_reset(usbvision);
+
+       /* Alternate interface 1 is is the biggest frame size */
+       errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive);
+       if (errCode < 0) {
+               usbvision->last_error = errCode;
+               return -EBUSY;
+       }
+
+       regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+       usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
+       PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
+
+       usbvision->usb_bandwidth = regValue >> 1;
+       PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
+
+
+
+       /* We double buffer the Iso lists */
+
+       for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+               int j, k;
+               struct urb *urb;
+
+               urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+               if (urb == NULL) {
+                       err("%s: usb_alloc_urb() failed", __FUNCTION__);
+                       return -ENOMEM;
+               }
+               usbvision->sbuf[bufIdx].urb = urb;
+               urb->dev = dev;
+               urb->context = usbvision;
+               urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->interval = 1;
+               urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
+               urb->complete = usbvision_isocIrq;
+               urb->number_of_packets = USBVISION_URB_FRAMES;
+               urb->transfer_buffer_length =
+                   usbvision->isocPacketSize * USBVISION_URB_FRAMES;
+               for (j = k = 0; j < USBVISION_URB_FRAMES; j++,
+                    k += usbvision->isocPacketSize) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = usbvision->isocPacketSize;
+               }
+       }
+
+
+       /* Submit all URBs */
+       for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+                       errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb, GFP_KERNEL);
+               if (errCode) {
+                       err("%s: usb_submit_urb(%d) failed: error %d", __FUNCTION__, bufIdx, errCode);
+               }
+       }
+
+       usbvision->streaming = Stream_Idle;
+       PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp);
+       return 0;
+}
+
+/*
+ * usbvision_stop_isoc()
+ *
+ * This procedure stops streaming and deallocates URBs. Then it
+ * activates zero-bandwidth alt. setting of the video interface.
+ *
+ */
+void usbvision_stop_isoc(struct usb_usbvision *usbvision)
+{
+       int bufIdx, errCode, regValue;
+
+       if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL))
+               return;
+
+       /* Unschedule all of the iso td's */
+       for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+               usb_kill_urb(usbvision->sbuf[bufIdx].urb);
+               usb_free_urb(usbvision->sbuf[bufIdx].urb);
+               usbvision->sbuf[bufIdx].urb = NULL;
+       }
+
+
+       PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__);
+       usbvision->streaming = Stream_Off;
+
+       if (!usbvision->remove_pending) {
+
+               /* Set packet size to 0 */
+               errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+                                     usbvision->ifaceAltInactive);
+               if (errCode < 0) {
+                       err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode);
+                       usbvision->last_error = errCode;
+               }
+               regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+               usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
+               PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
+
+               usbvision->usb_bandwidth = regValue >> 1;
+               PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
+       }
+}
+
+int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
+{
+       int mode[4];
+       int audio[]= {1, 0, 0, 0};
+       struct v4l2_routing route;
+       //channel 0 is TV with audiochannel 1 (tuner mono)
+       //channel 1 is Composite with audio channel 0 (line in)
+       //channel 2 is S-Video with audio channel 0 (line in)
+       //channel 3 is additional video inputs to the device with audio channel 0 (line in)
+
+       RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
+       usbvision->ctl_input = channel;
+         route.input = SAA7115_COMPOSITE1;
+         call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+         call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
+
+       // set the new channel
+       // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
+       // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red
+
+       switch (usbvision_device_data[usbvision->DevModel].Codec) {
+               case CODEC_SAA7113:
+                       if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices.  Use SwitchSVideoInput parameter when loading the module.
+                               mode[2] = 1;
+                       }
+                       else {
+                               mode[2] = 7;
+                       }
+                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                               mode[0] = 0; mode[1] = 2; mode[3] = 3;  // Special for four input devices
+                       }
+                       else {
+                               mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+                       }
+                       break;
+               case CODEC_SAA7111:
+                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
+                       break;
+               default:
+                       mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+       }
+       route.input = mode[channel];
+       call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+       usbvision->channel = channel;
+       usbvision_set_audio(usbvision, audio[channel]);
+       return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
new file mode 100644 (file)
index 0000000..0f3fba7
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * I2C_ALGO_USB.C
+ *  i2c algorithm for USB-I2C Bridges
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *                         Dwaine Garden <dwainegarden@rogers.com>
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ * 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/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include "usbvision.h"
+
+#define DBG_I2C                1<<0
+#define DBG_ALGO       1<<1
+
+static int i2c_debug = 0;
+
+module_param (i2c_debug, int, 0644);                   // debug_i2c_usb mode of the device driver
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define PDEBUG(level, fmt, args...) \
+               if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+
+static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+                           short len);
+static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+                          short len);
+
+static inline int try_write_address(struct i2c_adapter *i2c_adap,
+                                   unsigned char addr, int retries)
+{
+       struct i2c_algo_usb_data *adap = i2c_adap->algo_data;
+       void *data;
+       int i, ret = -1;
+       char buf[4];
+
+       data = i2c_get_adapdata(i2c_adap);
+       buf[0] = 0x00;
+       for (i = 0; i <= retries; i++) {
+               ret = (usbvision_i2c_write(data, addr, buf, 1));
+               if (ret == 1)
+                       break;  /* success! */
+               udelay(5 /*adap->udelay */ );
+               if (i == retries)       /* no success */
+                       break;
+               udelay(adap->udelay);
+       }
+       if (i) {
+               PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
+               PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+       }
+       return ret;
+}
+
+static inline int try_read_address(struct i2c_adapter *i2c_adap,
+                                  unsigned char addr, int retries)
+{
+       struct i2c_algo_usb_data *adap = i2c_adap->algo_data;
+       void *data;
+       int i, ret = -1;
+       char buf[4];
+
+       data = i2c_get_adapdata(i2c_adap);
+       for (i = 0; i <= retries; i++) {
+               ret = (usbvision_i2c_read(data, addr, buf, 1));
+               if (ret == 1)
+                       break;  /* success! */
+               udelay(5 /*adap->udelay */ );
+               if (i == retries)       /* no success */
+                       break;
+               udelay(adap->udelay);
+       }
+       if (i) {
+               PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
+               PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+       }
+       return ret;
+}
+
+static inline int usb_find_address(struct i2c_adapter *i2c_adap,
+                                  struct i2c_msg *msg, int retries,
+                                  unsigned char *add)
+{
+       unsigned short flags = msg->flags;
+
+       unsigned char addr;
+       int ret;
+       if ((flags & I2C_M_TEN)) {
+               /* a ten bit address */
+               addr = 0xf0 | ((msg->addr >> 7) & 0x03);
+               /* try extended address code... */
+               ret = try_write_address(i2c_adap, addr, retries);
+               if (ret != 1) {
+                       err("died at extended address code, while writing");
+                       return -EREMOTEIO;
+               }
+               add[0] = addr;
+               if (flags & I2C_M_RD) {
+                       /* okay, now switch into reading mode */
+                       addr |= 0x01;
+                       ret = try_read_address(i2c_adap, addr, retries);
+                       if (ret != 1) {
+                               err("died at extended address code, while reading");
+                               return -EREMOTEIO;
+                       }
+               }
+
+       } else {                /* normal 7bit address  */
+               addr = (msg->addr << 1);
+               if (flags & I2C_M_RD)
+                       addr |= 1;
+               if (flags & I2C_M_REV_DIR_ADDR)
+                       addr ^= 1;
+
+               add[0] = addr;
+               if (flags & I2C_M_RD)
+                       ret = try_read_address(i2c_adap, addr, retries);
+               else
+                       ret = try_write_address(i2c_adap, addr, retries);
+
+               if (ret != 1) {
+                       return -EREMOTEIO;
+               }
+       }
+       return 0;
+}
+
+static int
+usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+       struct i2c_msg *pmsg;
+       void *data;
+       int i, ret;
+       unsigned char addr;
+
+       data = i2c_get_adapdata(i2c_adap);
+
+       for (i = 0; i < num; i++) {
+               pmsg = &msgs[i];
+               ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr);
+               if (ret != 0) {
+                       PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i);
+                       return (ret < 0) ? ret : -EREMOTEIO;
+               }
+
+               if (pmsg->flags & I2C_M_RD) {
+                       /* read bytes into buffer */
+                       ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len));
+                       if (ret < pmsg->len) {
+                               return (ret < 0) ? ret : -EREMOTEIO;
+                       }
+               } else {
+                       /* write bytes from buffer */
+                       ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len));
+                       if (ret < pmsg->len) {
+                               return (ret < 0) ? ret : -EREMOTEIO;
+                       }
+               }
+       }
+       return num;
+}
+
+static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static u32 usb_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm i2c_usb_algo = {
+       .master_xfer   = usb_xfer,
+       .smbus_xfer    = NULL,
+       .algo_control  = algo_control,
+       .functionality = usb_func,
+};
+
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
+{
+       PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
+       PDEBUG(DBG_ALGO, "ALGO   debugging is enabled [i2c]");
+
+       /* register new adapter to i2c module... */
+
+       adap->algo = &i2c_usb_algo;
+
+       adap->timeout = 100;    /* default values, should       */
+       adap->retries = 3;      /* be replaced by defines       */
+
+       i2c_add_adapter(adap);
+
+       PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name);
+
+       return 0;
+}
+
+
+int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap)
+{
+
+       i2c_del_adapter(adap);
+
+       PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name);
+
+       return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* usbvision specific I2C functions                                        */
+/* ----------------------------------------------------------------------- */
+static struct i2c_adapter i2c_adap_template;
+static struct i2c_algo_usb_data i2c_algo_template;
+static struct i2c_client i2c_client_template;
+
+int usbvision_init_i2c(struct usb_usbvision *usbvision)
+{
+       memcpy(&usbvision->i2c_adap, &i2c_adap_template,
+              sizeof(struct i2c_adapter));
+       memcpy(&usbvision->i2c_algo, &i2c_algo_template,
+              sizeof(struct i2c_algo_usb_data));
+       memcpy(&usbvision->i2c_client, &i2c_client_template,
+              sizeof(struct i2c_client));
+
+       sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
+               " #%d", usbvision->vdev->minor & 0x1f);
+       PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+
+       i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
+       i2c_set_clientdata(&usbvision->i2c_client, usbvision);
+       i2c_set_algo_usb_data(&usbvision->i2c_algo, usbvision);
+
+       usbvision->i2c_adap.algo_data = &usbvision->i2c_algo;
+       usbvision->i2c_client.adapter = &usbvision->i2c_adap;
+
+       if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
+               printk(KERN_ERR "usbvision_init_i2c: can't write reg\n");
+               return -EBUSY;
+       }
+
+#ifdef CONFIG_MODULES
+       /* 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");
+               break;
+       }
+       if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
+               request_module("tuner");
+       }
+#endif
+
+       return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
+}
+
+void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
+                     void *arg)
+{
+       BUG_ON(NULL == usbvision->i2c_adap.algo_data);
+       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 0x43:
+               case 0x4b:
+               {
+                       struct tuner_setup tun_setup;
+
+                       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+                       tun_setup.type = TUNER_TDA9887;
+                       tun_setup.addr = client->addr;
+
+                       call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
+
+                       break;
+               }
+               case 0x42:
+                       PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
+                       break;
+               case 0x4a:
+                       PDEBUG(DBG_I2C,"attach_inform: saa7113 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)
+{
+       int rc, retries;
+
+       for (retries = 5;;) {
+               rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr);
+               if (rc < 0)
+                       return rc;
+
+               /* Initiate byte read cycle                    */
+               /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */
+               /*                    d3 0=Wr 1=Rd             */
+               rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT,
+                                     (len & 0x07) | 0x18);
+               if (rc < 0)
+                       return rc;
+
+               /* Test for Busy and ACK */
+               do {
+                       /* USBVISION_SER_CONT -> d4 == 0 busy */
+                       rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT);
+               } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */
+               if (rc < 0)
+                       return rc;
+
+               /* USBVISION_SER_CONT -> d5 == 1 Not ack */
+               if ((rc & 0x20) == 0)   /* Ack? */
+                       break;
+
+               /* I2C abort */
+               rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00);
+               if (rc < 0)
+                       return rc;
+
+               if (--retries < 0)
+                       return -1;
+       }
+
+       switch (len) {
+       case 4:
+               buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4);
+       case 3:
+               buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3);
+       case 2:
+               buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2);
+       case 1:
+               buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1);
+               break;
+       default:
+               printk(KERN_ERR
+                      "usbvision_i2c_read_max4: buffer length > 4\n");
+       }
+
+       if (i2c_debug & DBG_I2C) {
+               int idx;
+               for (idx = 0; idx < len; idx++) {
+                       PDEBUG(DBG_I2C,"read %x from address %x", (unsigned char)buf[idx], addr);
+               }
+       }
+       return len;
+}
+
+
+static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
+                                unsigned char addr, const char *buf,
+                                short len)
+{
+       int rc, retries;
+       int i;
+       unsigned char value[6];
+       unsigned char ser_cont;
+
+       ser_cont = (len & 0x07) | 0x10;
+
+       value[0] = addr;
+       value[1] = ser_cont;
+       for (i = 0; i < len; i++)
+               value[i + 2] = buf[i];
+
+       for (retries = 5;;) {
+               rc = usb_control_msg(usbvision->dev,
+                                    usb_sndctrlpipe(usbvision->dev, 1),
+                                    USBVISION_OP_CODE,
+                                    USB_DIR_OUT | USB_TYPE_VENDOR |
+                                    USB_RECIP_ENDPOINT, 0,
+                                    (__u16) USBVISION_SER_ADRS, value,
+                                    len + 2, HZ);
+
+               if (rc < 0)
+                       return rc;
+
+               rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT,
+                                     (len & 0x07) | 0x10);
+               if (rc < 0)
+                       return rc;
+
+               /* Test for Busy and ACK */
+               do {
+                       rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT);
+               } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */
+               if (rc < 0)
+                       return rc;
+
+               if ((rc & 0x20) == 0)   /* Ack? */
+                       break;
+
+               /* I2C abort */
+               usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00);
+
+               if (--retries < 0)
+                       return -1;
+
+       }
+
+       if (i2c_debug & DBG_I2C) {
+               int idx;
+               for (idx = 0; idx < len; idx++) {
+                       PDEBUG(DBG_I2C,"wrote %x at address %x", (unsigned char)buf[idx], addr);
+               }
+       }
+       return len;
+}
+
+static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+                           short len)
+{
+       char *bufPtr = buf;
+       int retval;
+       int wrcount = 0;
+       int count;
+       int maxLen = 4;
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
+
+       while (len > 0) {
+               count = (len > maxLen) ? maxLen : len;
+               retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count);
+               if (retval > 0) {
+                       len -= count;
+                       bufPtr += count;
+                       wrcount += count;
+               } else
+                       return (retval < 0) ? retval : -EFAULT;
+       }
+       return wrcount;
+}
+
+static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+                          short len)
+{
+       char temp[4];
+       int retval, i;
+       int rdcount = 0;
+       int count;
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
+
+       while (len > 0) {
+               count = (len > 3) ? 4 : len;
+               retval = usbvision_i2c_read_max4(usbvision, addr, temp, count);
+               if (retval > 0) {
+                       for (i = 0; i < len; i++)
+                               buf[rdcount + i] = temp[i];
+                       len -= count;
+                       rdcount += count;
+               } else
+                       return (retval < 0) ? retval : -EFAULT;
+       }
+       return rdcount;
+}
+
+static struct i2c_algo_usb_data i2c_algo_template = {
+       .data           = NULL,
+       .inb            = usbvision_i2c_read,
+       .outb           = usbvision_i2c_write,
+       .udelay         = 10,
+       .mdelay         = 10,
+       .timeout        = 100,
+};
+
+static struct i2c_adapter i2c_adap_template = {
+       .owner = THIS_MODULE,
+       .name              = "usbvision",
+       .id                = I2C_HW_B_BT848, /* FIXME */
+       .algo              = NULL,
+       .algo_data         = NULL,
+       .client_register   = attach_inform,
+       .client_unregister = detach_inform,
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+       .class             = I2C_ADAP_CLASS_TV_ANALOG,
+#else
+       .class             = I2C_CLASS_TV_ANALOG,
+#endif
+};
+
+static struct i2c_client i2c_client_template = {
+       .name           = "usbvision internal",
+};
+
+EXPORT_SYMBOL(usbvision_i2c_usb_add_bus);
+EXPORT_SYMBOL(usbvision_i2c_usb_del_bus);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
new file mode 100644 (file)
index 0000000..864446c
--- /dev/null
@@ -0,0 +1,2051 @@
+/*
+ * USB USBVISION Video device driver 0.9.9
+ *
+ *
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *
+ * This module is part of usbvision driver project.
+ *
+ * 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.
+ *
+ * Let's call the version 0.... until compression decoding is completely
+ * implemented.
+ *
+ * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach.
+ * It was based on USB CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt
+ * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler &
+ * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink
+ * Updates to driver completed by Dwaine P. Garden
+ *
+ *
+ * TODO:
+ *     - use submit_urb for all setup packets
+ *     - Fix memory settings for nt1004. It is 4 times as big as the
+ *       nt1003 memory.
+ *     - Add audio on endpoint 3 for nt1004 chip.  Seems impossible, needs a codec interface.  Which one?
+ *     - Clean up the driver.
+ *     - optimization for performance.
+ *     - Add Videotext capability (VBI).  Working on it.....
+ *     - Check audio for other devices
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#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>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "usbvision.h"
+
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_NAME "usbvision"
+#define DRIVER_ALIAS "USBVision"
+#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
+#define DRIVER_LICENSE "GPL"
+#define USBVISION_DRIVER_VERSION_MAJOR 0
+#define USBVISION_DRIVER_VERSION_MINOR 9
+#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+
+#define        ENABLE_HEXDUMP  0       /* Enable if you need it */
+
+
+#ifdef USBVISION_DEBUG
+       #define PDEBUG(level, fmt, args...) \
+               if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+       #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+#define DBG_IOCTL      1<<0
+#define DBG_IO         1<<1
+#define DBG_PROBE      1<<2
+#define DBG_MMAP       1<<3
+
+//String operations
+#define rmspace(str)   while(*str==' ') str++;
+#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
+
+
+static int usbvision_nr = 0;                   // sequential number of usbvision device
+
+static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
+       { 1, 1,  8, V4L2_PIX_FMT_GREY    , "GREY" },
+       { 1, 2, 16, V4L2_PIX_FMT_RGB565  , "RGB565" },
+       { 1, 3, 24, V4L2_PIX_FMT_RGB24   , "RGB24" },
+       { 1, 4, 32, V4L2_PIX_FMT_RGB32   , "RGB32" },
+       { 1, 2, 16, V4L2_PIX_FMT_RGB555  , "RGB555" },
+       { 1, 2, 16, V4L2_PIX_FMT_YUYV    , "YUV422" },
+       { 1, 2, 12, V4L2_PIX_FMT_YVU420  , "YUV420P" }, // 1.5 !
+       { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
+};
+
+/* supported tv norms */
+static struct usbvision_tvnorm tvnorms[] = {
+       {
+               .name = "PAL",
+               .id = V4L2_STD_PAL,
+       }, {
+               .name = "NTSC",
+               .id = V4L2_STD_NTSC,
+       }, {
+                .name = "SECAM",
+                .id = V4L2_STD_SECAM,
+       }, {
+               .name = "PAL-M",
+               .id = V4L2_STD_PAL_M,
+       }
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+// Function prototypes
+static void usbvision_release(struct usb_usbvision *usbvision);
+
+// Default initalization of device driver parameters
+static int isocMode = ISOC_MODE_COMPRESS;              // Set the default format for ISOC endpoint
+static int video_debug = 0;                            // Set the default Debug Mode of the device driver
+static int PowerOnAtOpen = 1;                          // Set the default device to power on at startup
+static int video_nr = -1;                              // Sequential Number of Video Device
+static int radio_nr = -1;                              // Sequential Number of Radio Device
+static int vbi_nr = -1;                                        // Sequential Number of VBI Device
+static char *CustomDevice=NULL;                                // Set as nothing....
+
+// Grab parameters for the device driver
+
+#if defined(module_param)                               // Showing parameters under SYSFS
+module_param(isocMode, int, 0444);
+module_param(video_debug, int, 0444);
+module_param(PowerOnAtOpen, int, 0444);
+module_param(video_nr, int, 0444);
+module_param(radio_nr, int, 0444);
+module_param(vbi_nr, int, 0444);
+module_param(CustomDevice, charp, 0444);
+#else                                                  // Old Style
+MODULE_PARAM(isocMode, "i");
+MODULE_PARM(video_debug, "i");                         // Grab the Debug Mode of the device driver
+MODULE_PARM(adjustCompression, "i");                   // Grab the compression to be adaptive
+MODULE_PARM(PowerOnAtOpen, "i");                       // Grab the device to power on at startup
+MODULE_PARM(SwitchSVideoInput, "i");                   // To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
+MODULE_PARM(video_nr, "i");                            // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
+MODULE_PARM(radio_nr, "i");                            // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
+MODULE_PARM(vbi_nr, "i");                              // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
+MODULE_PARM(CustomDevice, "s");                                // .... CustomDevice
+#endif
+
+MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
+MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver.  Default: 0 (Off)");
+MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened.  Default: 1 (On)");
+MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX).  Default: -1 (autodetect)");
+MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
+MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX).  Default: -1 (autodetect)");
+MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device.  Default: null");
+
+
+// Misc stuff
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_VERSION(USBVISION_VERSION_STRING);
+MODULE_ALIAS(DRIVER_ALIAS);
+
+
+/****************************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module.                                   */
+/* Device information is located at /sys/class/video4linux/video0                      */
+/* Device parameters information is located at /sys/module/usbvision                    */
+/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber    */
+/****************************************************************************************/
+
+
+#define YES_NO(x) ((x) ? "Yes" : "No")
+
+static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
+       return video_get_drvdata(vdev);
+}
+
+static ssize_t show_version(struct class_device *cd, char *buf)
+{
+       return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
+}
+static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_model(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+}
+static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+static ssize_t show_hue(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       struct v4l2_control ctrl;
+       ctrl.id = V4L2_CID_HUE;
+       ctrl.value = 0;
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+       return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+
+static ssize_t show_contrast(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       struct v4l2_control ctrl;
+       ctrl.id = V4L2_CID_CONTRAST;
+       ctrl.value = 0;
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+       return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+
+static ssize_t show_brightness(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       struct v4l2_control ctrl;
+       ctrl.id = V4L2_CID_BRIGHTNESS;
+       ctrl.value = 0;
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+       return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+
+static ssize_t show_saturation(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       struct v4l2_control ctrl;
+       ctrl.id = V4L2_CID_SATURATION;
+       ctrl.value = 0;
+       call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+       return sprintf(buf, "%d\n", ctrl.value >> 8);
+}
+static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+
+static ssize_t show_streaming(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+}
+static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_compression(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+}
+static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+
+static ssize_t show_device_bridge(struct class_device *class_dev, char *buf)
+{
+       struct video_device *vdev = to_video_device(class_dev);
+       struct usb_usbvision *usbvision = video_get_drvdata(vdev);
+       return sprintf(buf, "%d\n", usbvision->bridgeType);
+}
+static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+
+static void usbvision_create_sysfs(struct video_device *vdev)
+{
+       int res;
+       if (vdev) {
+               res=video_device_create_file(vdev, &class_device_attr_version);
+               res=video_device_create_file(vdev, &class_device_attr_model);
+               res=video_device_create_file(vdev, &class_device_attr_hue);
+               res=video_device_create_file(vdev, &class_device_attr_contrast);
+               res=video_device_create_file(vdev, &class_device_attr_brightness);
+               res=video_device_create_file(vdev, &class_device_attr_saturation);
+               res=video_device_create_file(vdev, &class_device_attr_streaming);
+               res=video_device_create_file(vdev, &class_device_attr_compression);
+               res=video_device_create_file(vdev, &class_device_attr_bridge);
+       }
+}
+
+static void usbvision_remove_sysfs(struct video_device *vdev)
+{
+       if (vdev) {
+               video_device_remove_file(vdev, &class_device_attr_version);
+               video_device_remove_file(vdev, &class_device_attr_model);
+               video_device_remove_file(vdev, &class_device_attr_hue);
+               video_device_remove_file(vdev, &class_device_attr_contrast);
+               video_device_remove_file(vdev, &class_device_attr_brightness);
+               video_device_remove_file(vdev, &class_device_attr_saturation);
+               video_device_remove_file(vdev, &class_device_attr_streaming);
+               video_device_remove_file(vdev, &class_device_attr_compression);
+               video_device_remove_file(vdev, &class_device_attr_bridge);
+       }
+}
+
+
+/*
+ * usbvision_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'usbvision->user'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ */
+static int usbvision_v4l2_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode = 0;
+
+       PDEBUG(DBG_IO, "open");
+
+
+       usbvision_reset_powerOffTimer(usbvision);
+
+       if (usbvision->user)
+               errCode = -EBUSY;
+       else {
+               /* Allocate memory for the frame buffers */
+               errCode = usbvision_frames_alloc(usbvision);
+               if(!errCode) {
+                       /* Allocate memory for the scratch ring buffer */
+                       errCode = usbvision_scratch_alloc(usbvision);
+                       if(!errCode) {
+                               /* Allocate memory for the USB S buffers */
+                               errCode = usbvision_sbuf_alloc(usbvision);
+                               if ((!errCode) && (usbvision->isocMode==ISOC_MODE_COMPRESS)) {
+                                       /* Allocate intermediate decompression buffers only if needed */
+                                       errCode = usbvision_decompress_alloc(usbvision);
+                               }
+                       }
+               }
+               if (errCode) {
+                       /* Deallocate all buffers if trouble */
+                       usbvision_frames_free(usbvision);
+                       usbvision_scratch_free(usbvision);
+                       usbvision_sbuf_free(usbvision);
+                       usbvision_decompress_free(usbvision);
+               }
+       }
+
+       /* If so far no errors then we shall start the camera */
+       if (!errCode) {
+               down(&usbvision->lock);
+               if (usbvision->power == 0) {
+                       usbvision_power_on(usbvision);
+                       usbvision_init_i2c(usbvision);
+               }
+
+               /* Send init sequence only once, it's large! */
+               if (!usbvision->initialized) {
+                       int setup_ok = 0;
+                       setup_ok = usbvision_setup(usbvision,isocMode);
+                       if (setup_ok)
+                               usbvision->initialized = 1;
+                       else
+                               errCode = -EBUSY;
+               }
+
+               if (!errCode) {
+                       usbvision_begin_streaming(usbvision);
+                       errCode = usbvision_init_isoc(usbvision);
+                       /* device needs to be initialized before isoc transfer */
+                       usbvision_muxsel(usbvision,0);
+                       usbvision->user++;
+               }
+               else {
+                       if (PowerOnAtOpen) {
+                               usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+                               usbvision_power_off(usbvision);
+                               usbvision->initialized = 0;
+                       }
+               }
+               up(&usbvision->lock);
+       }
+
+       if (errCode) {
+       }
+
+       /* prepare queues */
+       usbvision_empty_framequeues(usbvision);
+
+       PDEBUG(DBG_IO, "success");
+       return errCode;
+}
+
+/*
+ * usbvision_v4l2_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in usbvision_v4l2_open().
+ *
+ */
+static int usbvision_v4l2_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+       PDEBUG(DBG_IO, "close");
+       down(&usbvision->lock);
+
+       usbvision_audio_off(usbvision);
+       usbvision_restart_isoc(usbvision);
+       usbvision_stop_isoc(usbvision);
+
+       usbvision_decompress_free(usbvision);
+       usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
+       usbvision_scratch_free(usbvision);
+       usbvision_sbuf_free(usbvision);
+
+       usbvision->user--;
+
+       if (PowerOnAtOpen) {
+               /* power off in a little while to avoid off/on every close/open short sequences */
+               usbvision_set_powerOffTimer(usbvision);
+               usbvision->initialized = 0;
+       }
+
+       up(&usbvision->lock);
+
+       if (usbvision->remove_pending) {
+               info("%s: Final disconnect", __FUNCTION__);
+               usbvision_release(usbvision);
+       }
+
+       PDEBUG(DBG_IO, "success");
+
+
+       return 0;
+}
+
+
+/*
+ * usbvision_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return -EFAULT;
+
+       switch (cmd) {
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+               /* ioctls to allow direct acces to the NT100x registers */
+               case VIDIOC_INT_G_REGISTER:
+               {
+                       struct v4l2_register *reg = arg;
+                       int errCode;
+
+                       if (reg->i2c_id != 0)
+                               return -EINVAL;
+                       /* NT100x has a 8-bit register space */
+                       errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+                       if (errCode < 0) {
+                               err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
+                       }
+                       else {
+                               reg->val=(unsigned char)errCode;
+                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
+                                                       (unsigned int)reg->reg, reg->val);
+                               errCode = 0; // No error
+                       }
+                       return errCode;
+               }
+               case VIDIOC_INT_S_REGISTER:
+               {
+                       struct v4l2_register *reg = arg;
+                       int errCode;
+
+                       if (reg->i2c_id != 0)
+                               return -EINVAL;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+                       if (errCode < 0) {
+                               err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
+                       }
+                       else {
+                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
+                                                       (unsigned int)reg->reg, reg->val);
+                               errCode = 0;
+                       }
+                       return 0;
+               }
+#endif
+               case VIDIOC_QUERYCAP:
+               {
+                       struct v4l2_capability *vc=arg;
+
+                       memset(vc, 0, sizeof(*vc));
+                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
+                               sizeof(vc->card));
+                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+                               sizeof(vc->bus_info));
+                       vc->version = USBVISION_DRIVER_VERSION;
+                       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_AUDIO |
+                               V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING |
+                               (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+                       PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
+                       return 0;
+               }
+               case VIDIOC_ENUMINPUT:
+               {
+                       struct v4l2_input *vi = arg;
+                       int chan;
+
+                       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+                               return -EINVAL;
+                       if (usbvision->have_tuner) {
+                               chan = vi->index;
+                       }
+                       else {
+                               chan = vi->index + 1; //skip Television string
+                       }
+                       switch(chan) {
+                               case 0:
+                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                                               strcpy(vi->name, "White Video Input");
+                                       }
+                                       else {
+                                               strcpy(vi->name, "Television");
+                                               vi->type = V4L2_INPUT_TYPE_TUNER;
+                                               vi->audioset = 1;
+                                               vi->tuner = chan;
+                                               vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
+                                       }
+                                       break;
+                               case 1:
+                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
+                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                                               strcpy(vi->name, "Green Video Input");
+                                       }
+                                       else {
+                                               strcpy(vi->name, "Composite Video Input");
+                                       }
+                                       vi->std = V4L2_STD_PAL;
+                                       break;
+                               case 2:
+                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
+                                       if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+                                               strcpy(vi->name, "Yellow Video Input");
+                                       }
+                                       else {
+                                       strcpy(vi->name, "S-Video Input");
+                                       }
+                                       vi->std = V4L2_STD_PAL;
+                                       break;
+                               case 3:
+                                       vi->type = V4L2_INPUT_TYPE_CAMERA;
+                                       strcpy(vi->name, "Red Video Input");
+                                       vi->std = V4L2_STD_PAL;
+                                       break;
+                       }
+                       PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
+                              vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
+                       return 0;
+               }
+               case VIDIOC_ENUMSTD:
+               {
+                       struct v4l2_standard *e = arg;
+                       unsigned int i;
+                       int ret;
+
+                       i = e->index;
+                       if (i >= TVNORMS)
+                               return -EINVAL;
+                       ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+                                                      tvnorms[e->index].name);
+                       e->index = i;
+                       if (ret < 0)
+                               return ret;
+                       return 0;
+               }
+               case VIDIOC_G_INPUT:
+               {
+                       int *input = arg;
+                       *input = usbvision->ctl_input;
+                       return 0;
+               }
+               case VIDIOC_S_INPUT:
+               {
+                       int *input = arg;
+                       if ((*input >= usbvision->video_inputs) || (*input < 0) )
+                               return -EINVAL;
+                       usbvision->ctl_input = *input;
+
+                       down(&usbvision->lock);
+                       usbvision_muxsel(usbvision, usbvision->ctl_input);
+                       usbvision_set_input(usbvision);
+                       usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
+                       up(&usbvision->lock);
+                       return 0;
+               }
+               case VIDIOC_G_STD:
+               {
+                       v4l2_std_id *id = arg;
+
+                       *id = usbvision->tvnorm->id;
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
+                       return 0;
+               }
+               case VIDIOC_S_STD:
+               {
+                       v4l2_std_id *id = arg;
+                       unsigned int i;
+
+                       for (i = 0; i < TVNORMS; i++)
+                               if (*id == tvnorms[i].id)
+                                       break;
+                       if (i == TVNORMS)
+                               for (i = 0; i < TVNORMS; i++)
+                                       if (*id & tvnorms[i].id)
+                                               break;
+                       if (i == TVNORMS)
+                               return -EINVAL;
+
+                       down(&usbvision->lock);
+                       usbvision->tvnorm = &tvnorms[i];
+
+                       call_i2c_clients(usbvision, VIDIOC_S_STD,
+                                        &usbvision->tvnorm->id);
+
+                       up(&usbvision->lock);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
+                       return 0;
+               }
+               case VIDIOC_G_TUNER:
+               {
+                       struct v4l2_tuner *vt = arg;
+
+                       if (!usbvision->have_tuner || vt->index)        // Only tuner 0
+                               return -EINVAL;
+                       strcpy(vt->name, "Television");
+                       /* Let clients fill in the remainder of this struct */
+                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
+                       return 0;
+               }
+               case VIDIOC_S_TUNER:
+               {
+                       struct v4l2_tuner *vt = arg;
+
+                       // Only no or one tuner for now
+                       if (!usbvision->have_tuner || vt->index)
+                               return -EINVAL;
+                       /* let clients handle this */
+                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
+                       return 0;
+               }
+               case VIDIOC_G_FREQUENCY:
+               {
+                       struct v4l2_frequency *freq = arg;
+
+                       freq->tuner = 0; // Only one tuner
+                       freq->type = V4L2_TUNER_ANALOG_TV;
+                       freq->frequency = usbvision->freq;
+                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
+                       return 0;
+               }
+               case VIDIOC_S_FREQUENCY:
+               {
+                       struct v4l2_frequency *freq = arg;
+
+                       // Only no or one tuner for now
+                       if (!usbvision->have_tuner || freq->tuner)
+                               return -EINVAL;
+
+                       usbvision->freq = freq->frequency;
+                       call_i2c_clients(usbvision, cmd, freq);
+                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
+                       return 0;
+               }
+               case VIDIOC_G_AUDIO:
+               {
+                       struct v4l2_audio *v = arg;
+                       memset(v,0, sizeof(v));
+                       strcpy(v->name, "TV");
+                       PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
+                       return 0;
+               }
+               case VIDIOC_S_AUDIO:
+               {
+                       struct v4l2_audio *v = arg;
+                       if(v->index) {
+                               return -EINVAL;
+                       }
+                       PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
+                       return 0;
+               }
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *ctrl = arg;
+                       int id=ctrl->id;
+
+                       memset(ctrl,0,sizeof(*ctrl));
+                       ctrl->id=id;
+
+                       call_i2c_clients(usbvision, cmd, arg);
+
+                       if (ctrl->type)
+                               return 0;
+                       else
+                               return -EINVAL;
+
+                       PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
+               }
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+                       PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+                       return 0;
+               }
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+                       return 0;
+               }
+               case VIDIOC_REQBUFS:
+               {
+                       struct v4l2_requestbuffers *vr = arg;
+                       int ret;
+
+                       RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+                       // 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))
+                               return -EINVAL;
+
+                       if(usbvision->streaming == Stream_On) {
+                               if ((ret = usbvision_stream_interrupt(usbvision)))
+                                   return ret;
+                       }
+
+                       usbvision_empty_framequeues(usbvision);
+
+                       usbvision->curFrame = NULL;
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
+                       return 0;
+               }
+               case VIDIOC_QUERYBUF:
+               {
+                       struct v4l2_buffer *vb = arg;
+                       struct usbvision_frame *frame;
+
+                       // 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_NUMFRAMES)  {
+                               return -EINVAL;
+                       }
+                       // Updating the corresponding frame state
+                       vb->flags = 0;
+                       frame = &usbvision->frame[vb->index];
+                       if(frame->grabstate >= FrameState_Ready)
+                               vb->flags |= V4L2_BUF_FLAG_QUEUED;
+                       if(frame->grabstate >= FrameState_Done)
+                               vb->flags |= V4L2_BUF_FLAG_DONE;
+                       if(frame->grabstate == FrameState_Unused)
+                               vb->flags |= V4L2_BUF_FLAG_MAPPED;
+                       vb->memory = V4L2_MEMORY_MMAP;
+
+                       vb->m.offset = vb->index*usbvision->max_frame_size;
+
+                       vb->memory = V4L2_MEMORY_MMAP;
+                       vb->field = V4L2_FIELD_NONE;
+                       vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
+                       vb->timestamp = usbvision->frame[vb->index].timestamp;
+                       vb->sequence = usbvision->frame[vb->index].sequence;
+                       return 0;
+               }
+               case VIDIOC_QBUF:
+               {
+                       struct v4l2_buffer *vb = arg;
+                       struct usbvision_frame *frame;
+                       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_NUMFRAMES)  {
+                               return -EINVAL;
+                       }
+
+                       frame = &usbvision->frame[vb->index];
+
+                       if (frame->grabstate != FrameState_Unused) {
+                               return -EAGAIN;
+                       }
+
+                       /* Mark it as ready and enqueue frame */
+                       frame->grabstate = FrameState_Ready;
+                       frame->scanstate = ScanState_Scanning;
+                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+
+                       vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+                       /* set v4l2_format index */
+                       frame->v4l2_format = usbvision->palette;
+
+                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+                       list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
+                       return 0;
+               }
+               case VIDIOC_DQBUF:
+               {
+                       struct v4l2_buffer *vb = arg;
+                       int ret;
+                       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;
+                               ret = wait_event_interruptible
+                                       (usbvision->wait_frame,
+                                        !list_empty(&(usbvision->outqueue)));
+                               if (ret)
+                                       return ret;
+                       }
+
+                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+                       f = list_entry(usbvision->outqueue.next,
+                                      struct usbvision_frame, frame);
+                       list_del(usbvision->outqueue.next);
+                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+                       f->grabstate = FrameState_Unused;
+
+                       vb->memory = V4L2_MEMORY_MMAP;
+                       vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
+                       vb->index = f->index;
+                       vb->sequence = f->sequence;
+                       vb->timestamp = f->timestamp;
+                       vb->field = V4L2_FIELD_NONE;
+                       vb->bytesused = f->scanlength;
+
+                       return 0;
+               }
+               case VIDIOC_STREAMON:
+               {
+                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                       usbvision->streaming = Stream_On;
+
+                       call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+
+                       return 0;
+               }
+               case VIDIOC_STREAMOFF:
+               {
+                       int *type = arg;
+                       int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+
+                       if(usbvision->streaming == Stream_On) {
+                               usbvision_stream_interrupt(usbvision);
+                               // Stop all video streamings
+                               call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+                       }
+                       usbvision_empty_framequeues(usbvision);
+
+                       PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
+                       return 0;
+               }
+               case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *vfd = arg;
+
+                       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;
+               }
+               case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *vf = arg;
+
+                       switch (vf->type) {
+                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                               {
+                                       vf->fmt.pix.width = usbvision->curwidth;
+                                       vf->fmt.pix.height = usbvision->curheight;
+                                       vf->fmt.pix.pixelformat = usbvision->palette.format;
+                                       vf->fmt.pix.bytesperline =  usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+                                       vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+                                       vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
+                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+                                       return 0;
+                               }
+                               default:
+                                       PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
+                                       return -EINVAL;
+                       }
+                       return 0;
+               }
+               case VIDIOC_TRY_FMT:
+               case VIDIOC_S_FMT:
+               {
+                       struct v4l2_format *vf = arg;
+                       int formatIdx,ret;
+
+                       switch(vf->type) {
+                               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                               {
+                                       /* Find requested format in available ones */
+                                       for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+                                               if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
+                                                       usbvision->palette = usbvision_v4l2_format[formatIdx];
+                                                       break;
+                                               }
+                                       }
+                                       /* robustness */
+                                       if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+                                               return -EINVAL;
+                                       }
+                                       RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+                                       RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+                                       vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
+                                       vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+                                       if(cmd == VIDIOC_TRY_FMT) {
+                                               PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
+                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+                                               return 0;
+                                       }
+
+                                       /* stop io in case it is already in progress */
+                                       if(usbvision->streaming == Stream_On) {
+                                               if ((ret = usbvision_stream_interrupt(usbvision)))
+                                                       return ret;
+                                       }
+                                       usbvision_empty_framequeues(usbvision);
+
+                                       usbvision->curFrame = NULL;
+
+                                       // by now we are committed to the new data...
+                                       down(&usbvision->lock);
+                                       usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+                                       up(&usbvision->lock);
+
+                                       PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
+                                              vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
+                                       return 0;
+                               }
+                               default:
+                                       return -EINVAL;
+                       }
+               }
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+}
+
+
+static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
+                     size_t count, loff_t *ppos)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       int noblock = file->f_flags & O_NONBLOCK;
+       unsigned long lock_flags;
+
+       int frmx = -1;
+       int ret,i;
+       struct usbvision_frame *frame;
+
+       PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
+               return -EFAULT;
+
+       /* no stream is running, make it running ! */
+       usbvision->streaming = Stream_On;
+       call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+
+       /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+       for(i=0;i<USBVISION_NUMFRAMES;i++) {
+               frame = &usbvision->frame[i];
+               if(frame->grabstate == FrameState_Unused) {
+                       /* Mark it as ready and enqueue frame */
+                       frame->grabstate = FrameState_Ready;
+                       frame->scanstate = ScanState_Scanning;
+                       frame->scanlength = 0;  /* Accumulated in usbvision_parse_data() */
+
+                       /* set v4l2_format index */
+                       frame->v4l2_format = usbvision->palette;
+
+                       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+                       list_add_tail(&frame->frame, &usbvision->inqueue);
+                       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+               }
+       }
+
+       /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
+       if (list_empty(&(usbvision->outqueue))) {
+               if(noblock)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible
+                       (usbvision->wait_frame,
+                        !list_empty(&(usbvision->outqueue)));
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+       frame = list_entry(usbvision->outqueue.next,
+                          struct usbvision_frame, frame);
+       list_del(usbvision->outqueue.next);
+       spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+       /* An error returns an empty frame */
+       if (frame->grabstate == FrameState_Error) {
+               frame->bytes_read = 0;
+               return 0;
+       }
+
+       PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
+                      frame->index, frame->bytes_read, frame->scanlength);
+
+       /* copy bytes to user space; we allow for partials reads */
+       if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
+               count = frame->scanlength - frame->bytes_read;
+
+       if (copy_to_user(buf, frame->data + frame->bytes_read, count)) {
+               return -EFAULT;
+       }
+
+       frame->bytes_read += count;
+       PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
+                      (unsigned long)count, frame->bytes_read);
+
+       // For now, forget the frame if it has not been read in one shot.
+/*     if (frame->bytes_read >= frame->scanlength) {// All data has been read */
+               frame->bytes_read = 0;
+
+               /* Mark it as available to be used again. */
+               usbvision->frame[frmx].grabstate = FrameState_Unused;
+/*     } */
+
+       return count;
+}
+
+static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       unsigned long size = vma->vm_end - vma->vm_start,
+               start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+       down(&usbvision->lock);
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+               up(&usbvision->lock);
+               return -EFAULT;
+       }
+
+       if (!(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+               up(&usbvision->lock);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+               if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == USBVISION_NUMFRAMES) {
+               PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+               up(&usbvision->lock);
+               return -EINVAL;
+       }
+
+       /* VM_IO is eventually going to replace PageReserved altogether */
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+
+       pos = usbvision->frame[i].data;
+       while (size > 0) {
+
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
+                       up(&usbvision->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       up(&usbvision->lock);
+       return 0;
+}
+
+
+/*
+ * Here comes the stuff for radio on usbvision based devices
+ *
+ */
+static int usbvision_radio_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       struct v4l2_frequency freq;
+       int errCode = 0;
+
+       PDEBUG(DBG_IO, "%s:", __FUNCTION__);
+
+       down(&usbvision->lock);
+
+       if (usbvision->user) {
+               err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
+               errCode = -EBUSY;
+       }
+       else {
+               if(PowerOnAtOpen) {
+                       usbvision_reset_powerOffTimer(usbvision);
+                       if (usbvision->power == 0) {
+                               usbvision_power_on(usbvision);
+                               usbvision_init_i2c(usbvision);
+                       }
+               }
+
+               // If so far no errors then we shall start the radio
+               usbvision->radio = 1;
+               call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
+               freq.frequency = 1517; //SWR3 @ 94.8MHz
+               call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
+               usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
+               usbvision->user++;
+       }
+
+       if (errCode) {
+               if (PowerOnAtOpen) {
+                       usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+                       usbvision_power_off(usbvision);
+                       usbvision->initialized = 0;
+               }
+       }
+       up(&usbvision->lock);
+       return errCode;
+}
+
+
+static int usbvision_radio_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+       int errCode = 0;
+
+       PDEBUG(DBG_IO, "");
+
+       down(&usbvision->lock);
+
+       usbvision_audio_off(usbvision);
+       usbvision->radio=0;
+       usbvision->user--;
+
+       if (PowerOnAtOpen) {
+               usbvision_set_powerOffTimer(usbvision);
+               usbvision->initialized = 0;
+       }
+
+       up(&usbvision->lock);
+
+       if (usbvision->remove_pending) {
+               info("%s: Final disconnect", __FUNCTION__);
+               usbvision_release(usbvision);
+       }
+
+
+       PDEBUG(DBG_IO, "success");
+
+       return errCode;
+}
+
+static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+
+       if (!USBVISION_IS_OPERATIONAL(usbvision))
+               return -EIO;
+
+       switch (cmd) {
+               case VIDIOC_QUERYCAP:
+               {
+                       struct v4l2_capability *vc=arg;
+
+                       memset(vc, 0, sizeof(*vc));
+                       strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+                       strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
+                               sizeof(vc->card));
+                       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+                               sizeof(vc->bus_info));
+                       vc->version = USBVISION_DRIVER_VERSION;
+                       vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+                       PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
+                       return 0;
+               }
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *ctrl = arg;
+                       int id=ctrl->id;
+
+                       memset(ctrl,0,sizeof(*ctrl));
+                       ctrl->id=id;
+
+                       call_i2c_clients(usbvision, cmd, arg);
+                       PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
+
+                       if (ctrl->type)
+                               return 0;
+                       else
+                               return -EINVAL;
+
+               }
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+
+                       call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+                       PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+                       return 0;
+               }
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+
+                       call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+                       PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
+                       return 0;
+               }
+               case VIDIOC_G_TUNER:
+               {
+                       struct v4l2_tuner *t = arg;
+
+                       if (t->index > 0)
+                               return -EINVAL;
+
+                       memset(t,0,sizeof(*t));
+                       strcpy(t->name, "Radio");
+                       t->type = V4L2_TUNER_RADIO;
+
+                       /* Let clients fill in the remainder of this struct */
+                       call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
+                       PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
+                       return 0;
+               }
+               case VIDIOC_S_TUNER:
+               {
+                       struct v4l2_tuner *vt = arg;
+
+                       // Only no or one tuner for now
+                       if (!usbvision->have_tuner || vt->index)
+                               return -EINVAL;
+                       /* let clients handle this */
+                       call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+                       PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
+                       return 0;
+               }
+               case VIDIOC_G_AUDIO:
+               {
+                       struct v4l2_audio *a = arg;
+
+                       memset(a,0,sizeof(*a));
+                       strcpy(a->name,"Radio");
+                       PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
+                       return 0;
+               }
+               case VIDIOC_S_AUDIO:
+               case VIDIOC_S_INPUT:
+               case VIDIOC_S_STD:
+               return 0;
+
+               case VIDIOC_G_FREQUENCY:
+               {
+                       struct v4l2_frequency *f = arg;
+
+                       memset(f,0,sizeof(*f));
+
+                       f->type = V4L2_TUNER_RADIO;
+                       f->frequency = usbvision->freq;
+                       call_i2c_clients(usbvision, cmd, f);
+                       PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
+
+                       return 0;
+               }
+               case VIDIOC_S_FREQUENCY:
+               {
+                       struct v4l2_frequency *f = arg;
+
+                       if (f->tuner != 0)
+                               return -EINVAL;
+                       usbvision->freq = f->frequency;
+                       call_i2c_clients(usbvision, cmd, f);
+                       PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
+
+                       return 0;
+               }
+               default:
+               {
+                       PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
+                       return -ENOIOCTLCMD;
+               }
+       }
+       return 0;
+}
+
+
+static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
+}
+
+
+/*
+ * Here comes the stuff for vbi on usbvision based devices
+ *
+ */
+static int usbvision_vbi_open(struct inode *inode, struct file *file)
+{
+       /* TODO */
+       return -EINVAL;
+
+}
+
+static int usbvision_vbi_close(struct inode *inode, struct file *file)
+{
+       /* TODO */
+       return -EINVAL;
+}
+
+static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, void *arg)
+{
+       /* TODO */
+       return -EINVAL;
+}
+
+static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl);
+}
+
+
+//
+// Video registration stuff
+//
+
+// Video template
+static struct file_operations usbvision_fops = {
+       .owner             = THIS_MODULE,
+       .open           = usbvision_v4l2_open,
+       .release        = usbvision_v4l2_close,
+       .read           = usbvision_v4l2_read,
+       .mmap           = usbvision_v4l2_mmap,
+       .ioctl          = usbvision_v4l2_ioctl,
+       .llseek         = no_llseek,
+};
+static struct video_device usbvision_video_template = {
+       .owner             = THIS_MODULE,
+       .type           = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
+       .hardware       = VID_HARDWARE_USBVISION,
+       .fops           = &usbvision_fops,
+       .name           = "usbvision-video",
+       .release        = video_device_release,
+       .minor          = -1,
+};
+
+
+// Radio template
+static struct file_operations usbvision_radio_fops = {
+       .owner             = THIS_MODULE,
+       .open           = usbvision_radio_open,
+       .release        = usbvision_radio_close,
+       .ioctl          = usbvision_radio_ioctl,
+       .llseek         = no_llseek,
+};
+
+static struct video_device usbvision_radio_template=
+{
+       .owner             = THIS_MODULE,
+       .type           = VID_TYPE_TUNER,
+       .hardware       = VID_HARDWARE_USBVISION,
+       .fops           = &usbvision_radio_fops,
+       .release        = video_device_release,
+       .name           = "usbvision-radio",
+       .minor          = -1,
+};
+
+
+// vbi template
+static struct file_operations usbvision_vbi_fops = {
+       .owner             = THIS_MODULE,
+       .open           = usbvision_vbi_open,
+       .release        = usbvision_vbi_close,
+       .ioctl          = usbvision_vbi_ioctl,
+       .llseek         = no_llseek,
+};
+
+static struct video_device usbvision_vbi_template=
+{
+       .owner             = THIS_MODULE,
+       .type           = VID_TYPE_TUNER,
+       .hardware       = VID_HARDWARE_USBVISION,
+       .fops           = &usbvision_vbi_fops,
+       .release        = video_device_release,
+       .name           = "usbvision-vbi",
+       .minor          = -1,
+};
+
+
+static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
+                                       struct video_device *vdev_template,
+                                       char *name)
+{
+       struct usb_device *usb_dev = usbvision->dev;
+       struct video_device *vdev;
+
+       if (usb_dev == NULL) {
+               err("%s: usbvision->dev is not set", __FUNCTION__);
+               return NULL;
+       }
+
+       vdev = video_device_alloc();
+       if (NULL == vdev) {
+               return NULL;
+       }
+       *vdev = *vdev_template;
+//     vdev->minor   = -1;
+       vdev->dev     = &usb_dev->dev;
+       snprintf(vdev->name, sizeof(vdev->name), "%s", name);
+       video_set_drvdata(vdev, usbvision);
+       return vdev;
+}
+
+// unregister video4linux devices
+static void usbvision_unregister_video(struct usb_usbvision *usbvision)
+{
+       // vbi Device:
+       if (usbvision->vbi) {
+               PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+               if (usbvision->vbi->minor != -1) {
+                       video_unregister_device(usbvision->vbi);
+               }
+               else {
+                       video_device_release(usbvision->vbi);
+               }
+               usbvision->vbi = NULL;
+       }
+
+       // Radio Device:
+       if (usbvision->rdev) {
+               PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+               if (usbvision->rdev->minor != -1) {
+                       video_unregister_device(usbvision->rdev);
+               }
+               else {
+                       video_device_release(usbvision->rdev);
+               }
+               usbvision->rdev = NULL;
+       }
+
+       // Video Device:
+       if (usbvision->vdev) {
+               PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+               if (usbvision->vdev->minor != -1) {
+                       video_unregister_device(usbvision->vdev);
+               }
+               else {
+                       video_device_release(usbvision->vdev);
+               }
+               usbvision->vdev = NULL;
+       }
+}
+
+// register video4linux devices
+static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
+{
+       // Video Device:
+       usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+       if (usbvision->vdev == NULL) {
+               goto err_exit;
+       }
+       if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+               goto err_exit;
+       }
+       info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f);
+
+       // Radio Device:
+       if (usbvision_device_data[usbvision->DevModel].Radio) {
+               // usbvision has radio
+               usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+               if (usbvision->rdev == NULL) {
+                       goto err_exit;
+               }
+               if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+                       goto err_exit;
+               }
+               info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f);
+       }
+       // vbi Device:
+       if (usbvision_device_data[usbvision->DevModel].vbi) {
+               usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+               if (usbvision->vdev == NULL) {
+                       goto err_exit;
+               }
+               if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+                       goto err_exit;
+               }
+               info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f);
+       }
+       // all done
+       return 0;
+
+ err_exit:
+       err("USBVision[%d]: video_register_device() failed", usbvision->nr);
+       usbvision_unregister_video(usbvision);
+       return -1;
+}
+
+/*
+ * usbvision_alloc()
+ *
+ * This code allocates the struct usb_usbvision. It is filled with default values.
+ *
+ * Returns NULL on error, a pointer to usb_usbvision else.
+ *
+ */
+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->dev = dev;
+
+       init_MUTEX(&usbvision->lock);   /* to 1 == 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;
+       }
+       init_waitqueue_head(&usbvision->ctrlUrb_wq);
+       init_MUTEX(&usbvision->ctrlUrbLock);    /* to 1 == available */
+
+       usbvision_init_powerOffTimer(usbvision);
+
+       return usbvision;
+
+err_exit:
+       if (usbvision && usbvision->ctrlUrb) {
+               usb_free_urb(usbvision->ctrlUrb);
+       }
+       if (usbvision) {
+               kfree(usbvision);
+       }
+       return NULL;
+}
+
+/*
+ * usbvision_release()
+ *
+ * This code does final release of struct usb_usbvision. This happens
+ * after the device is disconnected -and- all clients closed their files.
+ *
+ */
+static void usbvision_release(struct usb_usbvision *usbvision)
+{
+       PDEBUG(DBG_PROBE, "");
+
+       down(&usbvision->lock);
+
+       usbvision_reset_powerOffTimer(usbvision);
+
+       usbvision->initialized = 0;
+
+       up(&usbvision->lock);
+
+       usbvision_remove_sysfs(usbvision->vdev);
+       usbvision_unregister_video(usbvision);
+
+       if (usbvision->ctrlUrb) {
+               usb_free_urb(usbvision->ctrlUrb);
+       }
+
+       kfree(usbvision);
+
+       PDEBUG(DBG_PROBE, "success");
+}
+
+
+/******************************** usb interface *****************************************/
+
+static void usbvision_configure_video(struct usb_usbvision *usbvision)
+{
+       int model,i;
+
+       if (usbvision == NULL)
+               return;
+
+       model = usbvision->DevModel;
+       usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
+
+       if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) {
+               usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff;
+       } else {
+               usbvision->Vin_Reg2_Preset = 0;
+       }
+
+       for (i = 0; i < TVNORMS; i++)
+               if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
+                       break;
+       if (i == TVNORMS)
+               i = 0;
+       usbvision->tvnorm = &tvnorms[i];        /* set default norm */
+
+       usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
+       usbvision->ctl_input = 0;
+
+       /* This should be here to make i2c clients to be able to register */
+       usbvision_audio_off(usbvision); //first switch off audio
+       if (!PowerOnAtOpen) {
+               usbvision_power_on(usbvision);  //and then power up the noisy tuner
+               usbvision_init_i2c(usbvision);
+       }
+}
+
+/*
+ * usbvision_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like USBVISION video device
+ *
+ */
+static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+       const struct usb_host_interface *interface;
+       struct usb_usbvision *usbvision = NULL;
+       const struct usb_endpoint_descriptor *endpoint;
+       int model;
+
+       PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
+                                       dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+       /* Is it an USBVISION video dev? */
+       model = 0;
+       for(model = 0; usbvision_device_data[model].idVendor; model++) {
+               if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) {
+                       continue;
+               }
+               if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) {
+                       continue;
+               }
+
+               info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString);
+               break;
+       }
+
+       if (usbvision_device_data[model].idVendor == 0) {
+               return -ENODEV; //no matching device
+       }
+       if (usbvision_device_data[model].Interface >= 0) {
+               interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
+       }
+       else {
+               interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+       }
+       endpoint = &interface->endpoint[1].desc;
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
+               err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
+               err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes);
+               return -ENODEV;
+       }
+       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+               err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+               return -ENODEV;
+       }
+
+       usb_get_dev(dev);
+
+       if ((usbvision = usbvision_alloc(dev)) == NULL) {
+               err("%s: couldn't allocate USBVision struct", __FUNCTION__);
+               return -ENOMEM;
+       }
+       if (dev->descriptor.bNumConfigurations > 1) {
+               usbvision->bridgeType = BRIDGE_NT1004;
+       }
+       else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") {
+               usbvision->bridgeType = BRIDGE_NT1005;
+       }
+       else {
+               usbvision->bridgeType = BRIDGE_NT1003;
+       }
+       PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
+
+       down(&usbvision->lock);
+
+       usbvision->nr = usbvision_nr++;
+
+       usbvision->have_tuner = usbvision_device_data[model].Tuner;
+       if (usbvision->have_tuner) {
+               usbvision->tuner_type = usbvision_device_data[model].TunerType;
+       }
+
+       usbvision->tuner_addr = ADDR_UNSET;
+
+       usbvision->DevModel = model;
+       usbvision->remove_pending = 0;
+       usbvision->iface = ifnum;
+       usbvision->ifaceAltInactive = 0;
+       usbvision->ifaceAltActive = 1;
+       usbvision->video_endp = endpoint->bEndpointAddress;
+       usbvision->isocPacketSize = 0;
+       usbvision->usb_bandwidth = 0;
+       usbvision->user = 0;
+       usbvision->streaming = Stream_Off;
+       usbvision_register_video(usbvision);
+       usbvision_configure_video(usbvision);
+       up(&usbvision->lock);
+
+
+       usb_set_intfdata (intf, usbvision);
+       usbvision_create_sysfs(usbvision->vdev);
+
+       PDEBUG(DBG_PROBE, "success");
+       return 0;
+}
+
+
+/*
+ * usbvision_disconnect()
+ *
+ * This procedure stops all driver activity, deallocates interface-private
+ * structure (pointed by 'ptr') and after that driver should be removable
+ * with no ill consequences.
+ *
+ */
+static void __devexit usbvision_disconnect(struct usb_interface *intf)
+{
+       struct usb_usbvision *usbvision = usb_get_intfdata(intf);
+
+       PDEBUG(DBG_PROBE, "");
+
+       if (usbvision == NULL) {
+               err("%s: usb_get_intfdata() failed", __FUNCTION__);
+               return;
+       }
+       usb_set_intfdata (intf, NULL);
+
+       down(&usbvision->lock);
+
+       // At this time we ask to cancel outstanding URBs
+       usbvision_stop_isoc(usbvision);
+
+       if (usbvision->power) {
+               usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+               usbvision_power_off(usbvision);
+       }
+       usbvision->remove_pending = 1;  // Now all ISO data will be ignored
+
+       usb_put_dev(usbvision->dev);
+       usbvision->dev = NULL;  // USB device is no more
+
+       up(&usbvision->lock);
+
+       if (usbvision->user) {
+               info("%s: In use, disconnect pending", __FUNCTION__);
+               wake_up_interruptible(&usbvision->wait_frame);
+               wake_up_interruptible(&usbvision->wait_stream);
+       }
+       else {
+               usbvision_release(usbvision);
+       }
+
+       PDEBUG(DBG_PROBE, "success");
+
+}
+
+static struct usb_driver usbvision_driver = {
+       .name           = "usbvision",
+       .id_table       = usbvision_table,
+       .probe          = usbvision_probe,
+       .disconnect     = usbvision_disconnect
+};
+
+/*
+ * customdevice_process()
+ *
+ * This procedure preprocesses CustomDevice parameter if any
+ *
+ */
+void customdevice_process(void)
+{
+       usbvision_device_data[0]=usbvision_device_data[1];
+       usbvision_table[0]=usbvision_table[1];
+
+       if(CustomDevice)
+       {
+               char *parse=CustomDevice;
+
+               PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice);
+
+               /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1"
+               usbvision_device_data[0].idVendor;
+               usbvision_device_data[0].idProduct;
+               usbvision_device_data[0].Interface;
+               usbvision_device_data[0].Codec;
+               usbvision_device_data[0].VideoChannels;
+               usbvision_device_data[0].VideoNorm;
+               usbvision_device_data[0].AudioChannels;
+               usbvision_device_data[0].Radio;
+               usbvision_device_data[0].Tuner;
+               usbvision_device_data[0].TunerType;
+               usbvision_device_data[0].Vin_Reg1;
+               usbvision_device_data[0].Vin_Reg2;
+               usbvision_device_data[0].X_Offset;
+               usbvision_device_data[0].Y_Offset;
+               usbvision_device_data[0].Dvi_yuv;
+               usbvision_device_data[0].ModelString;
+               */
+
+               rmspace(parse);
+               usbvision_device_data[0].ModelString="USBVISION Custom Device";
+
+               parse+=2;
+               sscanf(parse,"%x",&usbvision_device_data[0].idVendor);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor);
+               parse+=2;
+               sscanf(parse,"%x",&usbvision_device_data[0].idProduct);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct);
+               sscanf(parse,"%d",&usbvision_device_data[0].Interface);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface);
+               sscanf(parse,"%d",&usbvision_device_data[0].Codec);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec);
+               sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels);
+
+               switch(*parse)
+               {
+                       case 'P':
+                               PDEBUG(DBG_PROBE, "VideoNorm=PAL");
+                               usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL;
+                               break;
+
+                       case 'S':
+                               PDEBUG(DBG_PROBE, "VideoNorm=SECAM");
+                               usbvision_device_data[0].VideoNorm=VIDEO_MODE_SECAM;
+                               break;
+
+                       case 'N':
+                               PDEBUG(DBG_PROBE, "VideoNorm=NTSC");
+                               usbvision_device_data[0].VideoNorm=VIDEO_MODE_NTSC;
+                               break;
+
+                       default:
+                               PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)");
+                               usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL;
+                               break;
+               }
+               goto2next(parse);
+
+               sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels);
+               sscanf(parse,"%d",&usbvision_device_data[0].Radio);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio);
+               sscanf(parse,"%d",&usbvision_device_data[0].Tuner);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner);
+               sscanf(parse,"%d",&usbvision_device_data[0].TunerType);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType);
+               sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1);
+               sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2);
+               sscanf(parse,"%d",&usbvision_device_data[0].X_Offset);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset);
+               sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset);
+               goto2next(parse);
+               PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset);
+               sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv);
+               PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv);
+
+               //add to usbvision_table also
+               usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE;
+               usbvision_table[0].idVendor=usbvision_device_data[0].idVendor;
+               usbvision_table[0].idProduct=usbvision_device_data[0].idProduct;
+
+       }
+}
+
+
+
+/*
+ * usbvision_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ */
+static int __init usbvision_init(void)
+{
+       int errCode;
+
+       PDEBUG(DBG_PROBE, "");
+
+       PDEBUG(DBG_IOCTL, "IOCTL   debugging is enabled [video]");
+       PDEBUG(DBG_IO,  "IO      debugging is enabled [video]");
+       PDEBUG(DBG_PROBE, "PROBE   debugging is enabled [video]");
+       PDEBUG(DBG_MMAP, "MMAP    debugging is enabled [video]");
+
+       /* disable planar mode support unless compression enabled */
+       if (isocMode != ISOC_MODE_COMPRESS ) {
+               // FIXME : not the right way to set supported flag
+               usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420
+               usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P
+       }
+
+       customdevice_process();
+
+       errCode = usb_register(&usbvision_driver);
+
+       if (errCode == 0) {
+               info(DRIVER_DESC " : " USBVISION_VERSION_STRING);
+               PDEBUG(DBG_PROBE, "success");
+       }
+       return errCode;
+}
+
+static void __exit usbvision_exit(void)
+{
+ PDEBUG(DBG_PROBE, "");
+
+ usb_deregister(&usbvision_driver);
+ PDEBUG(DBG_PROBE, "success");
+}
+
+module_init(usbvision_init);
+module_exit(usbvision_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
new file mode 100644 (file)
index 0000000..0e7e3d6
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * USBVISION.H
+ *  usbvision header file
+ *
+ * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ *                         Dwaine Garden <dwainegarden@rogers.com>
+ *
+ *
+ * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list
+ *
+ * This module is part of usbvision driver project.
+ * Updates to driver completed by Dwaine P. Garden
+ * v4l2 conversion by Thierry Merle <thierry.merle@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, 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 __LINUX_USBVISION_H
+#define __LINUX_USBVISION_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <linux/videodev2.h>
+
+#define USBVISION_DEBUG                /* Turn on debug messages */
+
+#ifndef VID_HARDWARE_USBVISION
+       #define VID_HARDWARE_USBVISION 34   /* USBVision Video Grabber */
+#endif
+
+#define USBVISION_PWR_REG              0x00
+       #define USBVISION_SSPND_EN              (1 << 1)
+       #define USBVISION_RES2                  (1 << 2)
+       #define USBVISION_PWR_VID               (1 << 5)
+       #define USBVISION_E2_EN                 (1 << 7)
+#define USBVISION_CONFIG_REG           0x01
+#define USBVISION_ADRS_REG             0x02
+#define USBVISION_ALTER_REG            0x03
+#define USBVISION_FORCE_ALTER_REG      0x04
+#define USBVISION_STATUS_REG           0x05
+#define USBVISION_IOPIN_REG            0x06
+       #define USBVISION_IO_1                  (1 << 0)
+       #define USBVISION_IO_2                  (1 << 1)
+       #define USBVISION_AUDIO_IN              0
+       #define USBVISION_AUDIO_TV              1
+       #define USBVISION_AUDIO_RADIO           2
+       #define USBVISION_AUDIO_MUTE            3
+#define USBVISION_SER_MODE             0x07
+#define USBVISION_SER_ADRS             0x08
+#define USBVISION_SER_CONT             0x09
+#define USBVISION_SER_DAT1             0x0A
+#define USBVISION_SER_DAT2             0x0B
+#define USBVISION_SER_DAT3             0x0C
+#define USBVISION_SER_DAT4             0x0D
+#define USBVISION_EE_DATA              0x0E
+#define USBVISION_EE_LSBAD             0x0F
+#define USBVISION_EE_CONT              0x10
+#define USBVISION_DRM_CONT                     0x12
+       #define USBVISION_REF                   (1 << 0)
+       #define USBVISION_RES_UR                (1 << 2)
+       #define USBVISION_RES_FDL               (1 << 3)
+       #define USBVISION_RES_VDW               (1 << 4)
+#define USBVISION_DRM_PRM1             0x13
+#define USBVISION_DRM_PRM2             0x14
+#define USBVISION_DRM_PRM3             0x15
+#define USBVISION_DRM_PRM4             0x16
+#define USBVISION_DRM_PRM5             0x17
+#define USBVISION_DRM_PRM6             0x18
+#define USBVISION_DRM_PRM7             0x19
+#define USBVISION_DRM_PRM8             0x1A
+#define USBVISION_VIN_REG1             0x1B
+       #define USBVISION_8_422_SYNC            0x01
+       #define USBVISION_16_422_SYNC           0x02
+       #define USBVISION_VSNC_POL              (1 << 3)
+       #define USBVISION_HSNC_POL              (1 << 4)
+       #define USBVISION_FID_POL               (1 << 5)
+       #define USBVISION_HVALID_PO             (1 << 6)
+       #define USBVISION_VCLK_POL              (1 << 7)
+#define USBVISION_VIN_REG2             0x1C
+       #define USBVISION_AUTO_FID              (1 << 0)
+       #define USBVISION_NONE_INTER            (1 << 1)
+       #define USBVISION_NOHVALID              (1 << 2)
+       #define USBVISION_UV_ID                 (1 << 3)
+       #define USBVISION_FIX_2C                (1 << 4)
+       #define USBVISION_SEND_FID              (1 << 5)
+       #define USBVISION_KEEP_BLANK            (1 << 7)
+#define USBVISION_LXSIZE_I             0x1D
+#define USBVISION_MXSIZE_I             0x1E
+#define USBVISION_LYSIZE_I             0x1F
+#define USBVISION_MYSIZE_I             0x20
+#define USBVISION_LX_OFFST             0x21
+#define USBVISION_MX_OFFST             0x22
+#define USBVISION_LY_OFFST             0x23
+#define USBVISION_MY_OFFST             0x24
+#define USBVISION_FRM_RATE             0x25
+#define USBVISION_LXSIZE_O             0x26
+#define USBVISION_MXSIZE_O             0x27
+#define USBVISION_LYSIZE_O             0x28
+#define USBVISION_MYSIZE_O             0x29
+#define USBVISION_FILT_CONT            0x2A
+#define USBVISION_VO_MODE              0x2B
+#define USBVISION_INTRA_CYC            0x2C
+#define USBVISION_STRIP_SZ             0x2D
+#define USBVISION_FORCE_INTRA          0x2E
+#define USBVISION_FORCE_UP             0x2F
+#define USBVISION_BUF_THR              0x30
+#define USBVISION_DVI_YUV              0x31
+#define USBVISION_AUDIO_CONT           0x32
+#define USBVISION_AUD_PK_LEN           0x33
+#define USBVISION_BLK_PK_LEN           0x34
+#define USBVISION_PCM_THR1             0x38
+#define USBVISION_PCM_THR2             0x39
+#define USBVISION_DIST_THR_L           0x3A
+#define USBVISION_DIST_THR_H           0x3B
+#define USBVISION_MAX_DIST_L           0x3C
+#define USBVISION_MAX_DIST_H           0x3D
+#define USBVISION_OP_CODE              0x33
+
+#define MAX_BYTES_PER_PIXEL            4
+
+#define MIN_FRAME_WIDTH                        64
+#define MAX_USB_WIDTH                  320  //384
+#define MAX_FRAME_WIDTH                        320  //384                      /*streching sometimes causes crashes*/
+
+#define MIN_FRAME_HEIGHT               48
+#define MAX_USB_HEIGHT                 240  //288
+#define MAX_FRAME_HEIGHT               240  //288                      /*Streching sometimes causes crashes*/
+
+#define MAX_FRAME_SIZE                 (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
+#define USBVISION_CLIPMASK_SIZE                (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) //bytesize of clipmask
+
+#define USBVISION_URB_FRAMES           32
+#define USBVISION_MAX_ISOC_PACKET_SIZE         959                     // NT1003 Specs Document says 1023
+
+#define USBVISION_NUM_HEADERMARKER     20
+#define USBVISION_NUMFRAMES            3  /* Maximum number of frames an application can get */
+#define USBVISION_NUMSBUF              2 /* Dimensioning the USB S buffering */
+
+#define USBVISION_POWEROFF_TIME                3 * (HZ)                // 3 seconds
+
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  31
+
+enum {
+       ISOC_MODE_YUV422 = 0x03,
+       ISOC_MODE_YUV420 = 0x14,
+       ISOC_MODE_COMPRESS = 0x60,
+};
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16)                + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16)                + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+    mm_y = (my) - 16;  \
+    mm_u = (mu) - 128; \
+    mm_v = (mv) - 128; \
+    mm_yc= mm_y * 76284; \
+    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
+    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
+    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
+    mb = LIMIT_RGB(mm_b); \
+    mg = LIMIT_RGB(mm_g); \
+    mr = LIMIT_RGB(mm_r); \
+}
+
+/* Debugging aid */
+#define USBVISION_SAY_AND_WAIT(what) { \
+       wait_queue_head_t wq; \
+       init_waitqueue_head(&wq); \
+       printk(KERN_INFO "Say: %s\n", what); \
+       interruptible_sleep_on_timeout (&wq, HZ*3); \
+}
+
+/*
+ * This macro checks if usbvision is still operational. The 'usbvision'
+ * pointer must be valid, usbvision->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define USBVISION_IS_OPERATIONAL(udevice) (\
+       (udevice != NULL) && \
+       ((udevice)->dev != NULL) && \
+       ((udevice)->last_error == 0) && \
+       (!(udevice)->remove_pending))
+
+/* I2C structures */
+struct i2c_algo_usb_data {
+       void *data;             /* private data for lowlevel routines */
+       int (*inb) (void *data, unsigned char addr, char *buf, short len);
+       int (*outb) (void *data, unsigned char addr, char *buf, short len);
+
+       /* local settings */
+       int udelay;
+       int mdelay;
+       int timeout;
+};
+
+#define I2C_USB_ADAP_MAX       16
+
+/* ----------------------------------------------------------------- */
+/* usbvision video structures                                        */
+/* ----------------------------------------------------------------- */
+enum ScanState {
+       ScanState_Scanning,     /* Scanning for header */
+       ScanState_Lines         /* Parsing lines */
+};
+
+/* Completion states of the data parser */
+enum ParseState {
+       ParseState_Continue,    /* Just parse next item */
+       ParseState_NextFrame,   /* Frame done, send it to V4L */
+       ParseState_Out,         /* Not enough data for frame */
+       ParseState_EndParse     /* End parsing */
+};
+
+enum FrameState {
+       FrameState_Unused,      /* Unused (no MCAPTURE) */
+       FrameState_Ready,       /* Ready to start grabbing */
+       FrameState_Grabbing,    /* In the process of being grabbed into */
+       FrameState_Done,        /* Finished grabbing, but not been synced yet */
+       FrameState_DoneHold,    /* Are syncing or reading */
+       FrameState_Error,       /* Something bad happened while processing */
+};
+
+/* stream states */
+enum StreamState {
+       Stream_Off,             /* Driver streaming is completely OFF */
+       Stream_Idle,            /* Driver streaming is ready to be put ON by the application */
+       Stream_Interrupt,       /* Driver streaming must be interrupted */
+       Stream_On,              /* Driver streaming is put ON by the application */
+};
+
+enum IsocState {
+       IsocState_InFrame,      /* Isoc packet is member of frame */
+       IsocState_NoFrame,      /* Isoc packet is not member of any frame */
+};
+
+struct usb_device;
+
+struct usbvision_sbuf {
+       char *data;
+       struct urb *urb;
+};
+
+#define USBVISION_MAGIC_1                              0x55
+#define USBVISION_MAGIC_2                              0xAA
+#define USBVISION_HEADER_LENGTH                        0x0c
+#define USBVISION_SAA7111_ADDR                 0x48
+#define USBVISION_SAA7113_ADDR                 0x4a
+#define USBVISION_IIC_LRACK                    0x20
+#define USBVISION_IIC_LRNACK                   0x30
+#define USBVISION_FRAME_FORMAT_PARAM_INTRA     (1<<7)
+
+struct usbvision_v4l2_format_st {
+       int             supported;
+       int             bytes_per_pixel;
+       int             depth;
+       int             format;
+       char            *desc;
+};
+#define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format)
+
+struct usbvision_frame_header {
+       unsigned char magic_1;                          /* 0 magic */
+       unsigned char magic_2;                          /* 1  magic */
+       unsigned char headerLength;                     /* 2 */
+       unsigned char frameNum;                         /* 3 */
+       unsigned char framePhase;                       /* 4 */
+       unsigned char frameLatency;                     /* 5 */
+       unsigned char dataFormat;                       /* 6 */
+       unsigned char formatParam;                      /* 7 */
+       unsigned char frameWidthLo;                     /* 8 */
+       unsigned char frameWidthHi;                     /* 9 */
+       unsigned char frameHeightLo;                    /* 10 */
+       unsigned char frameHeightHi;                    /* 11 */
+       __u16 frameWidth;                               /* 8 - 9 after endian correction*/
+       __u16 frameHeight;                              /* 10 - 11 after endian correction*/
+};
+
+/* tvnorms */
+struct usbvision_tvnorm {
+       char *name;
+       v4l2_std_id id;
+       /* mode for saa7113h */
+       int mode;
+};
+
+struct usbvision_frame {
+       char *data;                                     /* Frame buffer */
+       struct usbvision_frame_header isocHeader;       /* Header from stream */
+
+       int width;                                      /* Width application is expecting */
+       int height;                                     /* Height */
+       int index;                                      /* Frame index */
+       int frmwidth;                                   /* Width the frame actually is */
+       int frmheight;                                  /* Height */
+
+       volatile int grabstate;                         /* State of grabbing */
+       int scanstate;                                  /* State of scanning */
+
+       struct list_head frame;
+
+       int curline;                                    /* Line of frame we're working on */
+
+       long scanlength;                                /* uncompressed, raw data length of frame */
+       long bytes_read;                                /* amount of scanlength that has been read from data */
+       struct usbvision_v4l2_format_st v4l2_format;    /* format the user needs*/
+       int v4l2_linesize;                              /* bytes for one videoline*/
+       struct timeval timestamp;
+       int sequence;                                   // How many video frames we send to user
+};
+
+#define CODEC_SAA7113  7113
+#define CODEC_SAA7111  7111
+#define BRIDGE_NT1003  1003
+#define BRIDGE_NT1004  1004
+#define BRIDGE_NT1005   1005
+
+struct usbvision_device_data_st {
+       int idVendor;
+       int idProduct;
+       int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
+       int Codec;
+       int VideoChannels;
+       __u64 VideoNorm;
+       int AudioChannels;
+       int Radio;
+       int vbi;
+       int Tuner;
+       int TunerType;
+       int Vin_Reg1;
+       int Vin_Reg2;
+       int X_Offset;
+       int Y_Offset;
+       int Dvi_yuv;
+       char *ModelString;
+};
+
+/* Declared on usbvision-cards.c */
+extern struct usbvision_device_data_st usbvision_device_data[];
+extern struct usb_device_id usbvision_table[];
+
+struct usb_usbvision {
+       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_algo_usb_data i2c_algo;
+       struct i2c_client i2c_client;
+
+       struct urb *ctrlUrb;
+       unsigned char ctrlUrbBuffer[8];
+       int ctrlUrbBusy;
+       struct usb_ctrlrequest ctrlUrbSetup;
+       wait_queue_head_t ctrlUrb_wq;                                   // Processes waiting
+       struct semaphore ctrlUrbLock;
+
+       /* configuration part */
+       int have_tuner;
+       int tuner_type;
+       int tuner_addr;
+       int bridgeType;                                                 // NT1003, NT1004, NT1005
+       int channel;
+       int radio;
+       int video_inputs;                                               // # of inputs
+       unsigned long freq;
+       int AudioMute;
+       int AudioChannel;
+       int isocMode;                                                   // format of video data for the usb isoc-transfer
+       unsigned int nr;                                                // Number of the device
+
+       /* Device structure */
+       struct usb_device *dev;
+       unsigned char iface;                                            /* Video interface number */
+       unsigned char ifaceAltActive, ifaceAltInactive;                 /* Alt settings */
+       unsigned char Vin_Reg2_Preset;
+       struct semaphore lock;
+       struct timer_list powerOffTimer;
+       struct work_struct powerOffWork;
+       int power;                                                      /* is the device powered on? */
+       int user;                                                       /* user count for exclusive use */
+       int initialized;                                                /* Had we already sent init sequence? */
+       int DevModel;                                                   /* What type of USBVISION device we got? */
+       enum StreamState streaming;                                     /* Are we streaming Isochronous? */
+       int last_error;                                                 /* What calamity struck us? */
+       int curwidth;                                                   /* width of the frame the device is currently set to*/
+       int curheight;                                                  /* height of the frame the device is currently set to*/
+       int stretch_width;                                              /* stretch-factor for frame width (from usb to screen)*/
+       int stretch_height;                                             /* stretch-factor for frame height (from usb to screen)*/
+       char *fbuf;                                                     /* Videodev buffer area for mmap*/
+       int max_frame_size;                                             /* Bytes in one video frame */
+       int fbuf_size;                                                  /* Videodev buffer size */
+       spinlock_t queue_lock;                                          /* spinlock for protecting mods on inqueue and outqueue */
+       struct list_head inqueue, outqueue;                             /* queued frame list and ready to dequeue frame list */
+       wait_queue_head_t wait_frame;                                   /* Processes waiting */
+       wait_queue_head_t wait_stream;                                  /* Processes waiting */
+       struct usbvision_frame *curFrame;                               // pointer to current frame, set by usbvision_find_header
+       struct usbvision_frame frame[USBVISION_NUMFRAMES];              // frame buffer
+       struct usbvision_sbuf sbuf[USBVISION_NUMSBUF];                  // S buffering
+       volatile int remove_pending;                                    /* If set then about to exit */
+
+       /* Scratch space from the Isochronous Pipe.*/
+       unsigned char *scratch;
+       int scratch_read_ptr;
+       int scratch_write_ptr;
+       int scratch_headermarker[USBVISION_NUM_HEADERMARKER];
+       int scratch_headermarker_read_ptr;
+       int scratch_headermarker_write_ptr;
+       enum IsocState isocstate;
+       struct usbvision_v4l2_format_st palette;
+
+       struct v4l2_capability vcap;                                    /* Video capabilities */
+       unsigned int ctl_input;                                         /* selected input */
+       struct usbvision_tvnorm *tvnorm;                                /* selected tv norm */
+       unsigned char video_endp;                                       /* 0x82 for USBVISION devices based */
+
+       // Decompression stuff:
+       unsigned char *IntraFrameBuffer;                                /* Buffer for reference frame */
+       int BlockPos;                                                   //for test only
+       int requestIntra;                                               // 0 = normal; 1 = intra frame is requested;
+       int lastIsocFrameNum;                                           // check for lost isoc frames
+       int isocPacketSize;                                             // need to calculate usedBandwidth
+       int usedBandwidth;                                              // used bandwidth 0-100%, need to set comprLevel
+       int comprLevel;                                                 // How strong (100) or weak (0) is compression
+       int lastComprLevel;                                             // How strong (100) or weak (0) was compression
+       int usb_bandwidth;                                              /* Mbit/s */
+
+       /* Statistics that can be overlayed on the screen */
+       unsigned long isocUrbCount;                     // How many URBs we received so far
+       unsigned long urb_length;                       /* Length of last URB */
+       unsigned long isocDataCount;                    /* How many bytes we received */
+       unsigned long header_count;                     /* How many frame headers we found */
+       unsigned long scratch_ovf_count;                /* How many times we overflowed scratch */
+       unsigned long isocSkipCount;                    /* How many empty ISO packets received */
+       unsigned long isocErrCount;                     /* How many bad ISO packets received */
+       unsigned long isocPacketCount;                  // How many packets we totally got
+       unsigned long timeInIrq;                        // How long do we need for interrupt
+       int isocMeasureBandwidthCount;
+       int frame_num;                                  // How many video frames we send to user
+       int maxStripLen;                                // How big is the biggest strip
+       int comprBlockPos;
+       int stripLenErrors;                             // How many times was BlockPos greater than StripLen
+       int stripMagicErrors;
+       int stripLineNumberErrors;
+       int ComprBlockTypes[4];
+};
+
+
+/* --------------------------------------------------------------- */
+/* defined in usbvision-i2c.c                                      */
+/* i2c-algo-usb declaration                                        */
+/* --------------------------------------------------------------- */
+
+int usbvision_i2c_usb_add_bus(struct i2c_adapter *);
+int usbvision_i2c_usb_del_bus(struct i2c_adapter *);
+
+static inline void *i2c_get_algo_usb_data (struct i2c_algo_usb_data *dev)
+{
+       return dev->data;
+}
+
+static inline void i2c_set_algo_usb_data (struct i2c_algo_usb_data *dev, void *data)
+{
+       dev->data = data;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* usbvision specific I2C functions                                        */
+/* ----------------------------------------------------------------------- */
+int usbvision_init_i2c(struct usb_usbvision *usbvision);
+void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
+
+/* defined in usbvision-core.c                                      */
+void *usbvision_rvmalloc(unsigned long size);
+void usbvision_rvfree(void *mem, unsigned long size);
+int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
+int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
+                       unsigned char value);
+
+int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+void usbvision_frames_free(struct usb_usbvision *usbvision);
+int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
+void usbvision_scratch_free(struct usb_usbvision *usbvision);
+int usbvision_sbuf_alloc(struct usb_usbvision *usbvision);
+void usbvision_sbuf_free(struct usb_usbvision *usbvision);
+int usbvision_decompress_alloc(struct usb_usbvision *usbvision);
+void usbvision_decompress_free(struct usb_usbvision *usbvision);
+
+int usbvision_setup(struct usb_usbvision *usbvision,int format);
+int usbvision_init_isoc(struct usb_usbvision *usbvision);
+int usbvision_restart_isoc(struct usb_usbvision *usbvision);
+void usbvision_stop_isoc(struct usb_usbvision *usbvision);
+
+int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
+int usbvision_audio_off(struct usb_usbvision *usbvision);
+
+int usbvision_begin_streaming(struct usb_usbvision *usbvision);
+void usbvision_empty_framequeues(struct usb_usbvision *dev);
+int usbvision_stream_interrupt(struct usb_usbvision *dev);
+
+int usbvision_muxsel(struct usb_usbvision *usbvision, int channel);
+int usbvision_set_input(struct usb_usbvision *usbvision);
+int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height);
+
+void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision);
+int usbvision_power_off(struct usb_usbvision *usbvision);
+int usbvision_power_on(struct usb_usbvision *usbvision);
+
+#endif                                                                 /* __LINUX_USBVISION_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index 1d899e2db394e62eff8f3398b005e1d37e78be3c..8a13e595304e59a479d3229d07f4db20a1d31b7c 100644 (file)
@@ -350,6 +350,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
                struct video_buffer     *buffer = arg;
 
                memset(buffer, 0, sizeof(*buffer));
+               memset(&fbuf2, 0, sizeof(fbuf2));
 
                err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
                if (err < 0) {
@@ -616,6 +617,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        case VIDIOCSPICT: /*  set tone controls & partial capture format  */
        {
                struct video_picture    *pict = arg;
+               memset(&fbuf2, 0, sizeof(fbuf2));
 
                set_v4l_control(inode, file,
                                V4L2_CID_BRIGHTNESS, pict->brightness, drv);
@@ -708,12 +710,22 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        }
        case VIDIOCSTUNER: /*  select a tuner input  */
        {
-               err = 0;
+               struct video_tuner      *tun = arg;
+               struct v4l2_tuner       t;
+               memset(&t,0,sizeof(t));
+
+               t.index=tun->tuner;
+
+               err = drv(inode, file, VIDIOC_S_INPUT, &t);
+               if (err < 0)
+                       dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err);
+
                break;
        }
        case VIDIOCGFREQ: /*  get frequency  */
        {
                unsigned long *freq = arg;
+               memset(&freq2,0,sizeof(freq2));
 
                freq2.tuner = 0;
                err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -726,8 +738,8 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        case VIDIOCSFREQ: /*  set frequency  */
        {
                unsigned long *freq = arg;
+               memset(&freq2,0,sizeof(freq2));
 
-               freq2.tuner = 0;
                drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
                freq2.frequency = *freq;
                err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
@@ -738,6 +750,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        case VIDIOCGAUDIO: /*  get audio properties/controls  */
        {
                struct video_audio      *aud = arg;
+               memset(&aud2,0,sizeof(aud2));
 
                err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
                if (err < 0) {
@@ -898,6 +911,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        {
                int                     *i = arg;
 
+               memset(&buf2,0,sizeof(buf2));
                buf2.index = *i;
                buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
index 78d28b03ec93df4e2b4eb0096aebd8589adf7fab..752c82c37f558277d14e36f4a150e98e2c9f9e81 100644 (file)
@@ -87,6 +87,78 @@ MODULE_LICENSE("GPL");
  */
 
 
+char *v4l2_norm_to_name(v4l2_std_id id)
+{
+       char *name;
+
+       switch (id) {
+       case V4L2_STD_PAL:
+               name="PAL";             break;
+       case V4L2_STD_PAL_BG:
+               name="PAL-BG";          break;
+       case V4L2_STD_PAL_DK:
+               name="PAL-DK";          break;
+       case V4L2_STD_PAL_B:
+               name="PAL-B";           break;
+       case V4L2_STD_PAL_B1:
+               name="PAL-B1";          break;
+       case V4L2_STD_PAL_G:
+               name="PAL-G";           break;
+       case V4L2_STD_PAL_H:
+               name="PAL-H";           break;
+       case V4L2_STD_PAL_I:
+               name="PAL-I";           break;
+       case V4L2_STD_PAL_D:
+               name="PAL-D";           break;
+       case V4L2_STD_PAL_D1:
+               name="PAL-D1";          break;
+       case V4L2_STD_PAL_K:
+               name="PAL-K";           break;
+       case V4L2_STD_PAL_M:
+               name="PAL-M";           break;
+       case V4L2_STD_PAL_N:
+               name="PAL-N";           break;
+       case V4L2_STD_PAL_Nc:
+               name="PAL-Nc";          break;
+       case V4L2_STD_PAL_60:
+               name="PAL-60";          break;
+       case V4L2_STD_NTSC:
+               name="NTSC";            break;
+       case V4L2_STD_NTSC_M:
+               name="NTSC-M";          break;
+       case V4L2_STD_NTSC_M_JP:
+               name="NTSC-M-JP";       break;
+       case V4L2_STD_NTSC_443:
+               name="NTSC-443";        break;
+       case V4L2_STD_NTSC_M_KR:
+               name="NTSC-M-KR";       break;
+       case V4L2_STD_SECAM:
+               name="SECAM";           break;
+       case V4L2_STD_SECAM_DK:
+               name="SECAM-DK";        break;
+       case V4L2_STD_SECAM_B:
+               name="SECAM-B";         break;
+       case V4L2_STD_SECAM_D:
+               name="SECAM-D";         break;
+       case V4L2_STD_SECAM_G:
+               name="SECAM-G";         break;
+       case V4L2_STD_SECAM_H:
+               name="SECAM-H";         break;
+       case V4L2_STD_SECAM_K:
+               name="SECAM-K";         break;
+       case V4L2_STD_SECAM_K1:
+               name="SECAM-K1";        break;
+       case V4L2_STD_SECAM_L:
+               name="SECAM-L";         break;
+       case V4L2_STD_SECAM_LC:
+               name="SECAM-LC";        break;
+       default:
+               name="Unknown";         break;
+       }
+
+       return name;
+}
+
 /* 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,
@@ -184,11 +256,13 @@ char *v4l2_field_names[] = {
 };
 
 char *v4l2_type_names[] = {
-       [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
-       [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
-       [V4L2_BUF_TYPE_VIDEO_OUTPUT]  = "video-out",
-       [V4L2_BUF_TYPE_VBI_CAPTURE]   = "vbi-cap",
-       [V4L2_BUF_TYPE_VBI_OUTPUT]    = "vbi-out",
+       [V4L2_BUF_TYPE_VIDEO_CAPTURE]      = "video-cap",
+       [V4L2_BUF_TYPE_VIDEO_OVERLAY]      = "video-over",
+       [V4L2_BUF_TYPE_VIDEO_OUTPUT]       = "video-out",
+       [V4L2_BUF_TYPE_VBI_CAPTURE]        = "vbi-cap",
+       [V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
+       [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
+       [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "slicec-vbi-out",
 };
 
 static char *v4l2_memory_names[] = {
@@ -1451,6 +1525,7 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 
 /* ----------------------------------------------------------------- */
 
+EXPORT_SYMBOL(v4l2_norm_to_name);
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
 EXPORT_SYMBOL(v4l2_prio_init);
index 41ec0c4b35a2a00989ec39d318d1390f628d9624..6a0e8ca7294803056cf29d11716d7ed175b35e5f 100644 (file)
@@ -342,7 +342,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
 
        dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
                "bytesused=%d, flags=0x%08d, "
-               "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+               "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
                        (p->timestamp.tv_sec/3600),
                        (int)(p->timestamp.tv_sec/60)%60,
                        (int)(p->timestamp.tv_sec%60),
@@ -352,7 +352,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
                        p->bytesused,p->flags,
                        p->field,p->sequence,
                        prt_names(p->memory,v4l2_memory_names),
-                       p->m.userptr);
+                       p->m.userptr, p->length);
        dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
                "flags=0x%08d, frames=%d, userbits=0x%08x\n",
                        tc->hours,tc->minutes,tc->seconds,
@@ -369,9 +369,13 @@ static inline void dbgrect(struct video_device *vfd, char *s,
 static inline void v4l_print_pix_fmt (struct video_device *vfd,
                                                struct v4l2_pix_format *fmt)
 {
-       dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+       dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
                "bytesperline=%d sizeimage=%d, colorspace=%d\n",
-               fmt->width,fmt->height,fmt->pixelformat,
+               fmt->width,fmt->height,
+               (fmt->pixelformat & 0xff),
+               (fmt->pixelformat >>  8) & 0xff,
+               (fmt->pixelformat >> 16) & 0xff,
+               (fmt->pixelformat >> 24) & 0xff,
                prt_names(fmt->field,v4l2_field_names_FIXME),
                fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
 };
@@ -428,6 +432,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                v4l_print_ioctl(vfd->name, cmd);
        }
 
+       if (_IOC_TYPE(cmd)=='v')
+               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+                                               __video_do_ioctl);
+
        switch(cmd) {
        /* --- capabilities ------------------------------------------ */
        case VIDIOC_QUERYCAP:
@@ -526,12 +534,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                }
                if (!ret)
                        dbgarg (cmd, "index=%d, type=%d, flags=%d, "
-                                       "description=%s,"
-                                       " pixelformat=0x%8x\n",
+                                       "pixelformat=%c%c%c%c, description='%s'\n",
                                        f->index, f->type, f->flags,
-                                       f->description,
-                                       f->pixelformat);
-
+                                       (f->pixelformat & 0xff),
+                                       (f->pixelformat >>  8) & 0xff,
+                                       (f->pixelformat >> 16) & 0xff,
+                                       (f->pixelformat >> 24) & 0xff,
+                                       f->description);
                break;
        }
        case VIDIOC_G_FMT:
@@ -829,20 +838,85 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUMSTD:
        {
                struct v4l2_standard *p = arg;
-               unsigned int index = p->index;
+               v4l2_std_id id = vfd->tvnorms,curr_id=0;
+               unsigned int index = p->index,i;
 
-               if (!vfd->tvnormsize) {
-                       printk (KERN_WARNING "%s: no TV norms defined!\n",
-                                               vfd->name);
+               if (index<0) {
+                       ret=-EINVAL;
                        break;
                }
 
-               if (index<0 || index >= vfd->tvnormsize) {
-                       ret=-EINVAL;
-                       break;
+               /* Return norm array on a canonical way */
+               for (i=0;i<= index && id; i++) {
+                       if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
+                               curr_id = V4L2_STD_PAL;
+                       } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
+                               curr_id = V4L2_STD_PAL_BG;
+                       } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
+                               curr_id = V4L2_STD_PAL_DK;
+                       } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
+                               curr_id = V4L2_STD_PAL_B;
+                       } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
+                               curr_id = V4L2_STD_PAL_B1;
+                       } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
+                               curr_id = V4L2_STD_PAL_G;
+                       } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
+                               curr_id = V4L2_STD_PAL_H;
+                       } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
+                               curr_id = V4L2_STD_PAL_I;
+                       } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
+                               curr_id = V4L2_STD_PAL_D;
+                       } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
+                               curr_id = V4L2_STD_PAL_D1;
+                       } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
+                               curr_id = V4L2_STD_PAL_K;
+                       } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
+                               curr_id = V4L2_STD_PAL_M;
+                       } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
+                               curr_id = V4L2_STD_PAL_N;
+                       } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
+                               curr_id = V4L2_STD_PAL_Nc;
+                       } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
+                               curr_id = V4L2_STD_PAL_60;
+                       } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+                               curr_id = V4L2_STD_NTSC;
+                       } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
+                               curr_id = V4L2_STD_NTSC_M;
+                       } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
+                               curr_id = V4L2_STD_NTSC_M_JP;
+                       } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
+                               curr_id = V4L2_STD_NTSC_443;
+                       } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
+                               curr_id = V4L2_STD_NTSC_M_KR;
+                       } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+                               curr_id = V4L2_STD_SECAM;
+                       } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
+                               curr_id = V4L2_STD_SECAM_DK;
+                       } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
+                               curr_id = V4L2_STD_SECAM_B;
+                       } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
+                               curr_id = V4L2_STD_SECAM_D;
+                       } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
+                               curr_id = V4L2_STD_SECAM_G;
+                       } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
+                               curr_id = V4L2_STD_SECAM_H;
+                       } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
+                               curr_id = V4L2_STD_SECAM_K;
+                       } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
+                               curr_id = V4L2_STD_SECAM_K1;
+                       } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
+                               curr_id = V4L2_STD_SECAM_L;
+                       } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
+                               curr_id = V4L2_STD_SECAM_LC;
+                       } else {
+                               break;
+                       }
+                       id &= ~curr_id;
                }
-               v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
-                                        vfd->tvnorms[p->index].name);
+               if (i<=index)
+                       return -EINVAL;
+
+               v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
                p->index = index;
 
                dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
@@ -868,39 +942,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        }
        case VIDIOC_S_STD:
        {
-               v4l2_std_id *id = arg;
-               unsigned int i;
-
-               if (!vfd->tvnormsize) {
-                       printk (KERN_WARNING "%s: no TV norms defined!\n",
-                                               vfd->name);
-                       break;
-               }
+               v4l2_std_id *id = arg,norm;
 
                dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
 
-               /* First search for exact match */
-               for (i = 0; i < vfd->tvnormsize; i++)
-                       if (*id == vfd->tvnorms[i].id)
-                               break;
-               /* Then for a generic video std that contains desired std */
-               if (i == vfd->tvnormsize)
-                       for (i = 0; i < vfd->tvnormsize; i++)
-                               if (*id & vfd->tvnorms[i].id)
-                                       break;
-               if (i == vfd->tvnormsize) {
+               norm = (*id) & vfd->tvnorms;
+               if ( vfd->tvnorms && !norm)     /* Check if std is supported */
                        break;
-               }
 
                /* Calls the specific handler */
                if (vfd->vidioc_s_std)
-                       ret=vfd->vidioc_s_std(file, fh, i);
+                       ret=vfd->vidioc_s_std(file, fh, &norm);
                else
                        ret=-EINVAL;
 
                /* Updates standard information */
-               if (!ret)
-                       vfd->current_norm=*id;
+               if (ret>=0)
+                       vfd->current_norm=norm;
 
                break;
        }
@@ -1088,9 +1146,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_AUDIO:
        {
                struct v4l2_audio *p=arg;
+               __u32 index=p->index;
 
                if (!vfd->vidioc_g_audio)
                        break;
+
+               memset(p,0,sizeof(*p));
+               p->index=index;
                dbgarg(cmd, "Get for index=%d\n", p->index);
                ret=vfd->vidioc_g_audio(file, fh, p);
                if (!ret)
@@ -1288,25 +1350,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                        ret=vfd->vidioc_g_parm(file, fh, p);
                } else {
                        struct v4l2_standard s;
-                       int i;
-
-                       if (!vfd->tvnormsize) {
-                               printk (KERN_WARNING "%s: no TV norms defined!\n",
-                                                       vfd->name);
-                               break;
-                       }
 
                        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                                return -EINVAL;
 
-                       for (i = 0; i < vfd->tvnormsize; i++)
-                               if (vfd->tvnorms[i].id == vfd->current_norm)
-                                       break;
-                       if (i >= vfd->tvnormsize)
-                               return -EINVAL;
-
                        v4l2_video_std_construct(&s, vfd->current_norm,
-                                                vfd->tvnorms[i].name);
+                                                v4l2_norm_to_name(vfd->current_norm));
 
                        memset(p,0,sizeof(*p));
 
@@ -1329,8 +1378,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *p=arg;
+               __u32 index=p->index;
+
                if (!vfd->vidioc_g_tuner)
                        break;
+
+               memset(p,0,sizeof(*p));
+               p->index=index;
+
                ret=vfd->vidioc_g_tuner(file, fh, p);
                if (!ret)
                        dbgarg (cmd, "index=%d, name=%s, type=%d, "
@@ -1363,6 +1418,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_frequency *p=arg;
                if (!vfd->vidioc_g_frequency)
                        break;
+
+               memset(p,0,sizeof(*p));
+
                ret=vfd->vidioc_g_frequency(file, fh, p);
                if (!ret)
                        dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1396,12 +1454,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret=vfd->vidioc_log_status(file, fh);
                break;
        }
-
-       /* --- Others --------------------------------------------- */
-
-       default:
-               ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
-       }
+       } /* switch */
 
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
                if (ret<0) {
index 9986de5cb3d6d46860ee9ad6e12fdf6e498683fe..474ddb779643a0495737bd718eb9225f4e5f6399 100644 (file)
@@ -1044,16 +1044,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return (0);
 }
 
-static struct v4l2_tvnorm tvnorms[] = {
-       {
-               .name      = "NTSC-M",
-               .id        = V4L2_STD_NTSC_M,
-       }
-};
-
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
 {
-
        return 0;
 }
 
@@ -1333,8 +1325,8 @@ static struct video_device vivi = {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
-       .tvnorms              = tvnorms,
-       .tvnormsize           = ARRAY_SIZE(tvnorms),
+       .tvnorms              = V4L2_STD_NTSC_M,
+       .current_norm         = V4L2_STD_NTSC_M,
 };
 /* -----------------------------------------------------------------
        Initialization and module stuff
@@ -1361,8 +1353,6 @@ static int __init vivi_init(void)
        dev->vidq.timeout.data     = (unsigned long)dev;
        init_timer(&dev->vidq.timeout);
 
-       vivi.current_norm         = tvnorms[0].id;
-
        ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
        printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
        return ret;
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
deleted file mode 100644 (file)
index 0cbf564..0000000
+++ /dev/null
@@ -1,2079 +0,0 @@
-/*
-    zr36120.c - Zoran 36120/36125 based framegrabbers
-
-    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.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.
-*/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <linux/wait.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/video_decoder.h>
-
-#include <asm/uaccess.h>
-
-#include "tuner.h"
-#include "zr36120.h"
-#include "zr36120_mem.h"
-
-/* mark an required function argument unused - lintism */
-#define        UNUSED(x)       (void)(x)
-
-/* sensible default */
-#ifndef CARDTYPE
-#define CARDTYPE 0
-#endif
-
-/* Anybody who uses more than four? */
-#define ZORAN_MAX 4
-
-static unsigned int triton1=0;                 /* triton1 chipset? */
-static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
-static int video_nr = -1;
-static int vbi_nr = -1;
-
-static struct pci_device_id zr36120_pci_tbl[] = {
-       { PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, zr36120_pci_tbl);
-
-MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
-MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber");
-MODULE_LICENSE("GPL");
-
-module_param(triton1, uint, 0);
-module_param_array(cardtype, uint, NULL, 0);
-module_param(video_nr, int, 0);
-module_param(vbi_nr, int, 0);
-
-static int zoran_cards;
-static struct zoran zorans[ZORAN_MAX];
-
-/*
- * the meaning of each element can be found in zr36120.h
- * Determining the value of gpdir/gpval can be tricky. The
- * best way is to run the card under the original software
- * and read the values from the general purpose registers
- * 0x28 and 0x2C. How you do that is left as an exercise
- * to the impatient reader :)
- */
-#define T 1    /* to separate the bools from the ints */
-#define F 0
-static struct tvcard tvcards[] = {
-       /* reported working by <middelin@polyware.nl> */
-/*0*/  { "Trust Victor II",
-         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
-       /* reported working by <Michael.Paxton@aihw.gov.au>  */
-/*1*/   { "Aitech WaveWatcher TV-PCI",
-         3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } },
-       /* reported working by ? */
-/*2*/  { "Genius Video Wonder PCI Video Capture Card",
-         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
-       /* reported working by <Pascal.Gabriel@wanadoo.fr> */
-/*3*/  { "Guillemot Maxi-TV PCI",
-         2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
-       /* reported working by "Craig Whitmore <lennon@igrin.co.nz> */
-/*4*/  { "Quadrant Buster",
-         3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } },
-       /* a debug entry which has all inputs mapped */
-/*5*/  { "ZR36120 based framegrabber (all inputs enabled)",
-         6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } }
-};
-#undef T
-#undef F
-#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0]))
-
-#ifdef __sparc__
-#define        ENDIANESS       0
-#else
-#define        ENDIANESS       ZORAN_VFEC_LE
-#endif
-
-static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = {
-/* n/a     */  { "n/a",     0, 0 },
-/* GREY    */  { "GRAY",    0, 0 },
-/* HI240   */  { "HI240",   0, 0 },
-/* RGB565  */  { "RGB565",  ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 },
-/* RGB24   */  { "RGB24",   ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 },
-/* RGB32   */  { "RGB32",   ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 },
-/* RGB555  */  { "RGB555",  ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 },
-/* YUV422  */  { "YUV422",  ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 },
-/* YUYV    */  { "YUYV",    0, 0 },
-/* UYVY    */  { "UYVY",    0, 0 },
-/* YUV420  */  { "YUV420",  0, 0 },
-/* YUV411  */  { "YUV411",  0, 0 },
-/* RAW     */  { "RAW",     0, 0 },
-/* YUV422P */  { "YUV422P", 0, 0 },
-/* YUV411P */  { "YUV411P", 0, 0 }};
-#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
-#undef ENDIANESS
-
-/* ----------------------------------------------------------------------- */
-/* ZORAN chipset detector                                                 */
-/* shamelessly stolen from bttv.c                                         */
-/* Reason for beeing here: we need to detect if we are running on a        */
-/* Triton based chipset, and if so, enable a certain bit                   */
-/* ----------------------------------------------------------------------- */
-static
-void __init handle_chipset(void)
-{
-       /* Just in case some nut set this to something dangerous */
-       if (triton1)
-               triton1 = ZORAN_VDC_TRICOM;
-
-       if (pci_pci_problems & PCIPCI_TRITON) {
-               printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
-               triton1 = ZORAN_VDC_TRICOM;
-       }
-}
-
-/* ----------------------------------------------------------------------- */
-/* ZORAN functions                                                        */
-/* ----------------------------------------------------------------------- */
-
-static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i);
-
-#if 0 /* unused */
-static
-void zoran_dump(struct zoran *ztv)
-{
-       char    str[256];
-       char    *p=str; /* shut up, gcc! */
-       int     i;
-
-       for (i=0; i<0x60; i+=4) {
-               if ((i % 16) == 0) {
-                       if (i) printk("%s\n",str);
-                       p = str;
-                       p+= sprintf(str, KERN_DEBUG "       %04x: ",i);
-               }
-               p += sprintf(p, "%08x ",zrread(i));
-       }
-}
-#endif /* unused */
-
-static
-void reap_states(struct zoran* ztv)
-{
-       /* count frames */
-       ztv->fieldnr++;
-
-       /*
-        * Are we busy at all?
-        * This depends on if there is a workqueue AND the
-        * videotransfer is enabled on the chip...
-        */
-       if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
-       {
-               struct vidinfo* newitem;
-
-               /* did we get a complete frame? */
-               if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
-                       return;
-
-DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
-
-               /* we are done with this buffer, tell everyone */
-               ztv->workqueue->status = FBUFFER_DONE;
-               ztv->workqueue->fieldnr = ztv->fieldnr;
-               /* not good, here for BTTV_FIELDNR reasons */
-               ztv->lastfieldnr = ztv->fieldnr;
-
-               switch (ztv->workqueue->kindof) {
-                case FBUFFER_GRAB:
-                       wake_up_interruptible(&ztv->grabq);
-                       break;
-                case FBUFFER_VBI:
-                       wake_up_interruptible(&ztv->vbiq);
-                       break;
-                default:
-                       printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof);
-               }
-
-               /* item completed, skip to next item in queue */
-               write_lock(&ztv->lock);
-               newitem = ztv->workqueue->next;
-               ztv->workqueue->next = 0;       /* mark completed */
-               ztv->workqueue = newitem;
-               write_unlock(&ztv->lock);
-       }
-
-       /*
-        * ok, so it seems we have nothing in progress right now.
-        * Lets see if we can find some work.
-        */
-       if (ztv->workqueue)
-       {
-               struct vidinfo* newitem;
-again:
-
-DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
-
-               /* loadup the frame settings */
-               read_lock(&ztv->lock);
-               zoran_set_geo(ztv,ztv->workqueue);
-               read_unlock(&ztv->lock);
-
-               switch (ztv->workqueue->kindof) {
-                case FBUFFER_GRAB:
-                case FBUFFER_VBI:
-                       zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
-                       zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
-                       zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
-
-                       /* start single-shot grab */
-                       zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
-                       break;
-                default:
-                       printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof);
-                       write_lock(&ztv->lock);
-                       newitem = ztv->workqueue->next;
-                       ztv->workqueue->next = 0;
-                       ztv->workqueue = newitem;
-                       write_unlock(&ztv->lock);
-                       if (newitem)
-                               goto again;     /* yeah, sure.. */
-               }
-               /* bye for now */
-               return;
-       }
-DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD));
-
-       /*
-        * What? Even the workqueue is empty? Am i really here
-        * for nothing? Did i come all that way to... do nothing?
-        */
-
-       /* do we need to overlay? */
-       if (test_bit(STATE_OVERLAY, &ztv->state))
-       {
-               /* are we already overlaying? */
-               if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) ||
-                   !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
-               {
-DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD));
-
-                       read_lock(&ztv->lock);
-                       zoran_set_geo(ztv,&ztv->overinfo);
-                       read_unlock(&ztv->lock);
-
-                       zror(ZORAN_OCR_OVLEN, ZORAN_OCR);
-                       zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
-                       zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
-               }
-
-               /*
-                * leave overlaying on, but turn interrupts off.
-                */
-               zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-               return;
-       }
-
-       /* do we have any VBI idle time processing? */
-       if (test_bit(STATE_VBI, &ztv->state))
-       {
-               struct vidinfo* item;
-               struct vidinfo* lastitem;
-
-               /* protect the workqueue */
-               write_lock(&ztv->lock);
-               lastitem = ztv->workqueue;
-               if (lastitem)
-                       while (lastitem->next) lastitem = lastitem->next;
-               for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
-                       if (item->next == 0 && item->status == FBUFFER_FREE)
-                       {
-DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item));
-                               item->status = FBUFFER_BUSY;
-                               if (!lastitem)
-                                       ztv->workqueue = item;
-                               else
-                                       lastitem->next = item;
-                               lastitem = item;
-                       }
-               write_unlock(&ztv->lock);
-               if (ztv->workqueue)
-                       goto again;     /* hey, _i_ graduated :) */
-       }
-
-       /*
-        * Then we must be realy IDLE
-        */
-DEBUG(printk(CARD_DEBUG "turning off\n",CARD));
-       /* nothing further to do, disable DMA and further IRQs */
-       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-       zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-}
-
-static
-void zoran_irq(int irq, void *dev_id)
-{
-       u32 stat,estat;
-       int count = 0;
-       struct zoran *ztv = dev_id;
-
-       UNUSED(irq);
-       for (;;) {
-               /* get/clear interrupt status bits */
-               stat=zrread(ZORAN_ISR);
-               estat=stat & zrread(ZORAN_ICR);
-               if (!estat)
-                       return;
-               zrwrite(estat,ZORAN_ISR);
-               IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat));
-               IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat));
-
-               if (estat & ZORAN_ISR_CODE)
-               {
-                       IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD));
-               }
-               if (estat & ZORAN_ISR_GIRQ0)
-               {
-                       IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD));
-                       if (!ztv->card->usegirq1)
-                               reap_states(ztv);
-               }
-               if (estat & ZORAN_ISR_GIRQ1)
-               {
-                       IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD));
-                       if (ztv->card->usegirq1)
-                               reap_states(ztv);
-               }
-
-               count++;
-               if (count > 10)
-                       printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat);
-               if (count > 20)
-               {
-                       zrwrite(0, ZORAN_ICR);
-                       printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD);
-               }
-       }
-}
-
-static
-int zoran_muxsel(struct zoran* ztv, int channel, int norm)
-{
-       int     rv;
-
-       /* set the new video norm */
-       rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
-       if (rv)
-               return rv;
-       ztv->norm = norm;
-
-       /* map the given channel to the cards decoder's channel */
-       channel = ztv->card->video_mux[channel] & CHANNEL_MASK;
-
-       /* set the new channel */
-       rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel);
-       return rv;
-}
-
-/* Tell the interrupt handler what to to.  */
-static
-void zoran_cap(struct zoran* ztv, int on)
-{
-DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state));
-
-       if (on) {
-               ztv->running = 1;
-
-               /*
-                * turn interrupts (back) on. The DMA will be enabled
-                * inside the irq handler when it detects a restart.
-                */
-               zror(ZORAN_ICR_EN,ZORAN_ICR);
-       }
-       else {
-               /*
-                * turn both interrupts and DMA off
-                */
-               zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-               zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-
-               ztv->running = 0;
-       }
-}
-
-static ulong dmask[] = {
-       0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,
-       0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,
-       0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800,
-       0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000,
-       0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000,
-       0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000,
-       0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000,
-       0xF0000000, 0xE0000000, 0xC0000000, 0x80000000
-};
-
-static
-void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp)
-{
-       ulong*  mtop;
-       int     ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */
-       int     i;
-
-DEBUG(printk(KERN_DEBUG "       overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
-
-       for (i=0; i<count; i++) {
-               struct video_clip *vp = vcp+i;
-               UNUSED(vp);
-DEBUG(printk(KERN_DEBUG "       %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->width,vp->height));
-       }
-
-       /*
-        * activate the visible portion of the screen
-        * Note we take some shortcuts here, because we
-        * know the width can never be < 32. (I.e. a DWORD)
-        * We also assume the overlay starts somewhere in
-        * the FIRST dword.
-        */
-       {
-               int start = ztv->vidXshift;
-               ulong firstd = dmask[start];
-               ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31];
-               mtop = ztv->overinfo.overlay;
-               for (i=0; i<ztv->overinfo.h; i++) {
-                       int w = ztv->vidWidth;
-                       ulong* line = mtop;
-                       if (start & 31) {
-                               *line++ = firstd;
-                               w -= 32-(start&31);
-                       }
-                       memset(line, ~0, w/8);
-                       if (w & 31)
-                               line[w/32] = lastd;
-                       mtop += ystep;
-               }
-       }
-
-       /* process clipping regions */
-       for (i=0; i<count; i++) {
-               int h;
-               if (vcp->x < 0 || (uint)vcp->x > ztv->overinfo.w ||
-                   vcp->y < 0 || vcp->y > ztv->overinfo.h ||
-                   vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w ||
-                   vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h)
-               {
-                       DEBUG(printk(CARD_DEBUG "invalid clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
-                       if (vcp->x < 0) vcp->x = 0;
-                       if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
-                       if (vcp->y < 0) vcp->y = 0;
-                       if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h;
-                       if (vcp->width < 0) vcp->width = 0;
-                       if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
-                       if (vcp->height < 0) vcp->height = 0;
-                       if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y;
-//                     continue;
-               }
-
-               mtop = &ztv->overinfo.overlay[vcp->y*ystep];
-               for (h=0; h<=vcp->height; h++) {
-                       int w;
-                       int x = ztv->vidXshift + vcp->x;
-                       for (w=0; w<=vcp->width; w++) {
-                               clear_bit(x&31, &mtop[x/32]);
-                               x++;
-                       }
-                       mtop += ystep;
-               }
-               ++vcp;
-       }
-
-       mtop = ztv->overinfo.overlay;
-       zrwrite(virt_to_bus(mtop), ZORAN_MTOP);
-       zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT);
-       zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
-}
-
-struct tvnorm
-{
-       u16 Wt, Wa, Ht, Ha, HStart, VStart;
-};
-
-static struct tvnorm tvnorms[] = {
-       /* PAL-BDGHI */
-/*     { 864, 720, 625, 576, 131, 21 },*/
-/*00*/ { 864, 768, 625, 576, 81, 17 },
-       /* NTSC */
-/*01*/ { 858, 720, 525, 480, 121, 10 },
-       /* SECAM */
-/*02*/ { 864, 720, 625, 576, 131, 21 },
-       /* BW50 */
-/*03*/ { 864, 720, 625, 576, 131, 21 },
-       /* BW60 */
-/*04*/ { 858, 720, 525, 480, 121, 10 }
-};
-#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
-
-/*
- * Program the chip for a setup as described in the vidinfo struct.
- *
- * Side-effects: calculates vidXshift, vidInterlace,
- * vidHeight, vidWidth which are used in a later stage
- * to calculate the overlay mask
- *
- * This is an internal function, as such it does not check the
- * validity of the struct members... Spectaculair crashes will
- * follow /very/ quick when you're wrong and the chip right :)
- */
-static
-void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
-{
-       ulong   top, bot;
-       int     stride;
-       int     winWidth, winHeight;
-       int     maxWidth, maxHeight, maxXOffset, maxYOffset;
-       long    vfec;
-
-DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay));
-
-       /*
-        * make sure the DMA transfers are inhibited during our
-        * reprogramming of the chip
-        */
-       zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
-
-       maxWidth = tvnorms[ztv->norm].Wa;
-       maxHeight = tvnorms[ztv->norm].Ha/2;
-       maxXOffset = tvnorms[ztv->norm].HStart;
-       maxYOffset = tvnorms[ztv->norm].VStart;
-
-       /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */
-       vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) |
-              (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24));
-
-       /*
-        * Set top, bottom ptrs. Since these must be DWORD aligned,
-        * possible adjust the x and the width of the window.
-        * so the endposition stay the same. The vidXshift will make
-        * sure we are not writing pixels before the requested x.
-        */
-       ztv->vidXshift = 0;
-       winWidth = i->w;
-       if (winWidth < 0)
-               winWidth = -winWidth;
-       top = i->busadr + i->x*i->bpp + i->y*i->bpl;
-       if (top & 3) {
-               ztv->vidXshift = (top & 3) / i->bpp;
-               winWidth += ztv->vidXshift;
-               DEBUG(printk(KERN_DEBUG "       window-x shifted %d pixels left\n",ztv->vidXshift));
-               top &= ~3;
-       }
-
-       /*
-        * bottom points to next frame but in interleaved mode we want
-        * to 'mix' the 2 frames to one capture, so 'bot' points to one
-        * (physical) line below the top line.
-        */
-       bot = top + i->bpl;
-       zrwrite(top,ZORAN_VTOP);
-       zrwrite(bot,ZORAN_VBOT);
-
-       /*
-        * Make sure the winWidth is DWORD aligned too,
-        * thereby automaticly making sure the stride to the
-        * next line is DWORD aligned too (as required by spec).
-        */
-       if ((winWidth*i->bpp) & 3) {
-DEBUG(printk(KERN_DEBUG "       window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
-               winWidth += (winWidth*i->bpp) & 3;
-       }
-
-       /* determine the DispMode and stride */
-       if (i->h >= 0 && i->h <= maxHeight) {
-               /* single frame grab suffices for this height. */
-               vfec |= ZORAN_VFEC_DISPMOD;
-               ztv->vidInterlace = 0;
-               stride = i->bpl - (winWidth*i->bpp);
-               winHeight = i->h;
-       }
-       else {
-               /* interleaving needed for this height */
-               ztv->vidInterlace = 1;
-               stride = i->bpl*2 - (winWidth*i->bpp);
-               winHeight = i->h/2;
-       }
-       if (winHeight < 0)      /* can happen for VBI! */
-               winHeight = -winHeight;
-
-       /* safety net, sometimes bpl is too short??? */
-       if (stride<0) {
-DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride));
-               stride = 0;
-       }
-
-       zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC);
-       zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR);
-
-       /* remember vidWidth, vidHeight for overlay calculations */
-       ztv->vidWidth = winWidth;
-       ztv->vidHeight = winHeight;
-DEBUG(printk(KERN_DEBUG "       top=%08lx, bottom=%08lx\n",top,bot));
-DEBUG(printk(KERN_DEBUG "       winWidth=%d, winHeight=%d\n",winWidth,winHeight));
-DEBUG(printk(KERN_DEBUG "       maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight));
-DEBUG(printk(KERN_DEBUG "       stride=%d\n",stride));
-
-       /*
-        * determine horizontal scales and crops
-        */
-       if (i->w < 0) {
-               int Hstart = 1;
-               int Hend = Hstart + winWidth;
-DEBUG(printk(KERN_DEBUG "       Y: scale=0, start=%d, end=%d\n", Hstart, Hend));
-               zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
-       }
-       else {
-               int Wa = maxWidth;
-               int X = (winWidth*64+Wa-1)/Wa;
-               int We = winWidth*64/X;
-               int HorDcm = 64-X;
-               int hcrop1 = 2*(Wa-We)/4;
-               /*
-                * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi>
-                * found the solution to the color phase shift.
-                * See ChangeLog for the full explanation)
-                */
-               int Hstart = (maxXOffset + hcrop1) | 1;
-               int Hend = Hstart + We - 1;
-
-DEBUG(printk(KERN_DEBUG "       X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend));
-
-               zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
-               vfec |= HorDcm<<14;
-
-               if (HorDcm<16)
-                       vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */
-               else if (HorDcm<32)
-                       vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
-               else if (HorDcm<48)
-                       vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
-               else    vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
-       }
-
-       /*
-        * Determine vertical scales and crops
-        *
-        * when height is negative, we want to read starting at line 0
-        * One day someone might need access to these lines...
-        */
-       if (i->h < 0) {
-               int Vstart = 0;
-               int Vend = Vstart + winHeight;
-DEBUG(printk(KERN_DEBUG "       Y: scale=0, start=%d, end=%d\n", Vstart, Vend));
-               zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
-       }
-       else {
-               int Ha = maxHeight;
-               int Y = (winHeight*64+Ha-1)/Ha;
-               int He = winHeight*64/Y;
-               int VerDcm = 64-Y;
-               int vcrop1 = 2*(Ha-He)/4;
-               int Vstart = maxYOffset + vcrop1;
-               int Vend = Vstart + He - 1;
-
-DEBUG(printk(KERN_DEBUG "       Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
-               zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
-               vfec |= VerDcm<<8;
-       }
-
-DEBUG(printk(KERN_DEBUG "       F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name));
-
-       /* setup the requested format */
-       zrwrite(vfec, ZORAN_VFEC);
-}
-
-static
-void zoran_common_open(struct zoran* ztv, int flags)
-{
-       UNUSED(flags);
-
-       /* already opened? */
-       if (ztv->users++ != 0)
-               return;
-
-       /* unmute audio */
-       /* /what/ audio? */
-
-       ztv->state = 0;
-
-       /* setup the encoder to the initial values */
-       ztv->picture.colour=254<<7;
-       ztv->picture.brightness=128<<8;
-       ztv->picture.hue=128<<8;
-       ztv->picture.contrast=216<<7;
-       i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
-
-       /* default to the composite input since my camera is there */
-       zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
-}
-
-static
-void zoran_common_close(struct zoran* ztv)
-{
-       if (--ztv->users != 0)
-               return;
-
-       /* mute audio */
-       /* /what/ audio? */
-
-       /* stop the chip */
-       zoran_cap(ztv, 0);
-}
-
-/*
- * Open a zoran card. Right now the flags are just a hack
- */
-static int zoran_open(struct video_device *dev, int flags)
-{
-       struct zoran *ztv = (struct zoran*)dev;
-       struct vidinfo* item;
-       char* pos;
-
-       DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags));
-
-       /*********************************************
-        * We really should be doing lazy allocing...
-        *********************************************/
-       /* allocate a frame buffer */
-       if (!ztv->fbuffer)
-               ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
-       if (!ztv->fbuffer) {
-               /* could not get a buffer, bail out */
-               return -ENOBUFS;
-       }
-       /* at this time we _always_ have a framebuffer */
-       memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
-
-       if (!ztv->overinfo.overlay)
-               ztv->overinfo.overlay = kmalloc(1024*1024/8, GFP_KERNEL);
-       if (!ztv->overinfo.overlay) {
-               /* could not get an overlay buffer, bail out */
-               bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
-               return -ENOBUFS;
-       }
-       /* at this time we _always_ have a overlay */
-
-       /* clear buffer status, and give them a DMAable address */
-       pos = ztv->fbuffer;
-       for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
-       {
-               item->status = FBUFFER_FREE;
-               item->memadr = pos;
-               item->busadr = virt_to_bus(pos);
-               pos += ZORAN_MAX_FBUFFER;
-       }
-
-       /* do the common part of all open's */
-       zoran_common_open(ztv, flags);
-
-       return 0;
-}
-
-static
-void zoran_close(struct video_device* dev)
-{
-       struct zoran *ztv = (struct zoran*)dev;
-
-       DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD));
-
-       /* driver specific closure */
-       clear_bit(STATE_OVERLAY, &ztv->state);
-
-       zoran_common_close(ztv);
-
-       /*
-        *      This is sucky but right now I can't find a good way to
-        *      be sure its safe to free the buffer. We wait 5-6 fields
-        *      which is more than sufficient to be sure.
-        */
-       msleep(100);                    /* Wait 1/10th of a second */
-
-       /* free the allocated framebuffer */
-       bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
-       ztv->fbuffer = 0;
-       kfree(ztv->overinfo.overlay);
-       ztv->overinfo.overlay = 0;
-
-}
-
-/*
- * This read function could be used reentrant in a SMP situation.
- *
- * This is made possible by the spinlock which is kept till we
- * found and marked a buffer for our own use. The lock must
- * be released as soon as possible to prevent lock contention.
- */
-static
-long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
-{
-       struct zoran *ztv = (struct zoran*)dev;
-       unsigned long max;
-       struct vidinfo* unused = 0;
-       struct vidinfo* done = 0;
-
-       DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock));
-
-       /* find ourself a free or completed buffer */
-       for (;;) {
-               struct vidinfo* item;
-
-               write_lock_irq(&ztv->lock);
-               for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
-               {
-                       if (!unused && item->status == FBUFFER_FREE)
-                               unused = item;
-                       if (!done && item->status == FBUFFER_DONE)
-                               done = item;
-               }
-               if (done || unused)
-                       break;
-
-               /* no more free buffers, wait for them. */
-               write_unlock_irq(&ztv->lock);
-               if (nonblock)
-                       return -EWOULDBLOCK;
-               interruptible_sleep_on(&ztv->grabq);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       /* Do we have 'ready' data? */
-       if (!done) {
-               /* no? than this will take a while... */
-               if (nonblock) {
-                       write_unlock_irq(&ztv->lock);
-                       return -EWOULDBLOCK;
-               }
-
-               /* mark the unused buffer as wanted */
-               unused->status = FBUFFER_BUSY;
-               unused->w = 320;
-               unused->h = 240;
-               unused->format = VIDEO_PALETTE_RGB24;
-               unused->bpp = palette2fmt[unused->format].bpp;
-               unused->bpl = unused->w * unused->bpp;
-               unused->next = 0;
-               { /* add to tail of queue */
-                 struct vidinfo* oldframe = ztv->workqueue;
-                 if (!oldframe) ztv->workqueue = unused;
-                 else {
-                   while (oldframe->next) oldframe = oldframe->next;
-                   oldframe->next = unused;
-                 }
-               }
-               write_unlock_irq(&ztv->lock);
-
-               /* tell the state machine we want it filled /NOW/ */
-               zoran_cap(ztv, 1);
-
-               /* wait till this buffer gets grabbed */
-               wait_event_interruptible(ztv->grabq,
-                               (unused->status != FBUFFER_BUSY));
-               /* see if a signal did it */
-               if (signal_pending(current))
-                       return -EINTR;
-               done = unused;
-       }
-       else
-               write_unlock_irq(&ztv->lock);
-
-       /* Yes! we got data! */
-       max = done->bpl * done->h;
-       if (count > max)
-               count = max;
-       if (copy_to_user((void*)buf, done->memadr, count))
-               count = -EFAULT;
-
-       /* keep the engine running */
-       done->status = FBUFFER_FREE;
-//     zoran_cap(ztv,1);
-
-       /* tell listeners this buffer became free */
-       wake_up_interruptible(&ztv->grabq);
-
-       /* goodbye */
-       DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count));
-       return count;
-}
-
-static
-long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
-{
-       struct zoran *ztv = (struct zoran *)dev;
-       UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock);
-       DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD));
-       return -EINVAL;
-}
-
-static
-unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
-{
-       struct zoran *ztv = (struct zoran *)dev;
-       struct vidinfo* item;
-       unsigned int mask = 0;
-
-       poll_wait(file, &ztv->grabq, wait);
-
-       for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
-               if (item->status == FBUFFER_DONE)
-               {
-                       mask |= (POLLIN | POLLRDNORM);
-                       break;
-               }
-
-       DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask));
-
-       return mask;
-}
-
-/* append a new clipregion to the vector of video_clips */
-static
-void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h)
-{
-       vcp[vw->clipcount].x = x;
-       vcp[vw->clipcount].y = y;
-       vcp[vw->clipcount].width = w;
-       vcp[vw->clipcount].height = h;
-       vw->clipcount++;
-}
-
-static
-int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
-{
-       struct zoran* ztv = (struct zoran*)dev;
-
-       switch (cmd) {
-        case VIDIOCGCAP:
-        {
-               struct video_capability c;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD));
-
-               strcpy(c.name,ztv->video_dev.name);
-               c.type = VID_TYPE_CAPTURE|
-                        VID_TYPE_OVERLAY|
-                        VID_TYPE_CLIPPING|
-                        VID_TYPE_FRAMERAM|
-                        VID_TYPE_SCALES;
-               if (ztv->have_tuner)
-                       c.type |= VID_TYPE_TUNER;
-               if (pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
-                       c.type &= ~VID_TYPE_OVERLAY;
-               if (ztv->have_decoder) {
-                       c.channels = ztv->card->video_inputs;
-                       c.audios = ztv->card->audio_inputs;
-               } else
-                       /* no decoder -> no channels */
-                       c.channels = c.audios = 0;
-               c.maxwidth = 768;
-               c.maxheight = 576;
-               c.minwidth = 32;
-               c.minheight = 32;
-               if (copy_to_user(arg,&c,sizeof(c)))
-                       return -EFAULT;
-               break;
-        }
-
-        case VIDIOCGCHAN:
-        {
-               struct video_channel v;
-               int mux;
-               if (copy_from_user(&v, arg,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel));
-               v.flags=VIDEO_VC_AUDIO
-#ifdef VIDEO_VC_NORM
-                       |VIDEO_VC_NORM
-#endif
-                       ;
-               v.tuners=0;
-               v.type=VIDEO_TYPE_CAMERA;
-#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API
-               v.norm=VIDEO_MODE_PAL|
-                      VIDEO_MODE_NTSC|
-                      VIDEO_MODE_SECAM;
-#else
-               v.norm=VIDEO_MODE_PAL;
-#endif
-               /* too many inputs? no decoder -> no channels */
-               if (!ztv->have_decoder || v.channel < 0 ||  v.channel >= ztv->card->video_inputs)
-                       return -EINVAL;
-
-               /* now determine the name of the channel */
-               mux = ztv->card->video_mux[v.channel];
-               if (mux & IS_TUNER) {
-                       /* lets assume only one tuner, yes? */
-                       strcpy(v.name,"Television");
-                       v.type = VIDEO_TYPE_TV;
-                       if (ztv->have_tuner) {
-                               v.flags |= VIDEO_VC_TUNER;
-                               v.tuners = 1;
-                       }
-               }
-               else if (mux & IS_SVHS)
-                       sprintf(v.name,"S-Video-%d",v.channel);
-               else
-                       sprintf(v.name,"CVBS-%d",v.channel);
-
-               if (copy_to_user(arg,&v,sizeof(v)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSCHAN:
-        {      /* set video channel */
-               struct video_channel v;
-               if (copy_from_user(&v, arg,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
-
-               /* too many inputs? no decoder -> no channels */
-               if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs || v.channel < 0)
-                       return -EINVAL;
-
-               if (v.norm != VIDEO_MODE_PAL &&
-                   v.norm != VIDEO_MODE_NTSC &&
-                   v.norm != VIDEO_MODE_SECAM &&
-                   v.norm != VIDEO_MODE_AUTO)
-                       return -EOPNOTSUPP;
-
-               /* make it happen, nr1! */
-               return zoran_muxsel(ztv,v.channel,v.norm);
-        }
-
-        case VIDIOCGTUNER:
-        {
-               struct video_tuner v;
-               if (copy_from_user(&v, arg,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner));
-
-               /* Only no or one tuner for now */
-               if (!ztv->have_tuner || v.tuner)
-                       return -EINVAL;
-
-               strcpy(v.name,"Television");
-               v.rangelow  = 0;
-               v.rangehigh = ~0;
-               v.flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-               v.mode      = ztv->norm;
-               v.signal    = 0xFFFF; /* unknown */
-
-               if (copy_to_user(arg,&v,sizeof(v)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSTUNER:
-        {
-               struct video_tuner v;
-               if (copy_from_user(&v, arg, sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode));
-
-               /* Only no or one tuner for now */
-               if (!ztv->have_tuner || v.tuner)
-                       return -EINVAL;
-
-               /* and it only has certain valid modes */
-               if( v.mode != VIDEO_MODE_PAL &&
-                   v.mode != VIDEO_MODE_NTSC &&
-                   v.mode != VIDEO_MODE_SECAM)
-                       return -EOPNOTSUPP;
-
-               /* engage! */
-               return zoran_muxsel(ztv,v.tuner,v.mode);
-        }
-
-        case VIDIOCGPICT:
-        {
-               struct video_picture p = ztv->picture;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD));
-               p.depth = ztv->depth;
-               switch (p.depth) {
-                case  8: p.palette=VIDEO_PALETTE_YUV422;
-                         break;
-                case 15: p.palette=VIDEO_PALETTE_RGB555;
-                         break;
-                case 16: p.palette=VIDEO_PALETTE_RGB565;
-                         break;
-                case 24: p.palette=VIDEO_PALETTE_RGB24;
-                         break;
-                case 32: p.palette=VIDEO_PALETTE_RGB32;
-                         break;
-               }
-               if (copy_to_user(arg, &p, sizeof(p)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSPICT:
-        {
-               struct video_picture p;
-               if (copy_from_user(&p, arg,sizeof(p)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette));
-
-               /* depth must match with framebuffer */
-               if (p.depth != ztv->depth)
-                       return -EINVAL;
-
-               /* check if palette matches this bpp */
-               if (p.palette>NRPALETTES ||
-                   palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
-                       return -EINVAL;
-
-               write_lock_irq(&ztv->lock);
-               ztv->overinfo.format = p.palette;
-               ztv->picture = p;
-               write_unlock_irq(&ztv->lock);
-
-               /* tell the decoder */
-               i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
-               break;
-        }
-
-        case VIDIOCGWIN:
-        {
-               struct video_window vw;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD));
-               read_lock(&ztv->lock);
-               vw.x      = ztv->overinfo.x;
-               vw.y      = ztv->overinfo.y;
-               vw.width  = ztv->overinfo.w;
-               vw.height = ztv->overinfo.h;
-               vw.chromakey= 0;
-               vw.flags  = 0;
-               if (ztv->vidInterlace)
-                       vw.flags|=VIDEO_WINDOW_INTERLACE;
-               read_unlock(&ztv->lock);
-               if (copy_to_user(arg,&vw,sizeof(vw)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSWIN:
-        {
-               struct video_window vw;
-               struct video_clip *vcp;
-               int on;
-               if (copy_from_user(&vw,arg,sizeof(vw)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
-
-               if (vw.flags)
-                       return -EINVAL;
-
-               if (vw.clipcount <0 || vw.clipcount>256)
-                       return -EDOM;   /* Too many! */
-
-               /*
-                *      Do any clips.
-                */
-               vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
-               if (vcp==NULL)
-                       return -ENOMEM;
-               if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) {
-                       vfree(vcp);
-                       return -EFAULT;
-               }
-
-               on = ztv->running;
-               if (on)
-                       zoran_cap(ztv, 0);
-
-               /*
-                * strange, it seems xawtv sometimes calls us with 0
-                * width and/or height. Ignore these values
-                */
-               if (vw.x == 0)
-                       vw.x = ztv->overinfo.x;
-               if (vw.y == 0)
-                       vw.y = ztv->overinfo.y;
-
-               /* by now we are committed to the new data... */
-               write_lock_irq(&ztv->lock);
-               ztv->overinfo.x = vw.x;
-               ztv->overinfo.y = vw.y;
-               ztv->overinfo.w = vw.width;
-               ztv->overinfo.h = vw.height;
-               write_unlock_irq(&ztv->lock);
-
-               /*
-                *      Impose display clips
-                */
-               if (vw.x+vw.width > ztv->swidth)
-                       new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
-               if (vw.y+vw.height > ztv->sheight)
-                       new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1);
-
-               /* built the requested clipping zones */
-               zoran_set_geo(ztv, &ztv->overinfo);
-               zoran_built_overlay(ztv, vw.clipcount, vcp);
-               vfree(vcp);
-
-               /* if we were on, restart the video engine */
-               if (on)
-                       zoran_cap(ztv, 1);
-               break;
-        }
-
-        case VIDIOCCAPTURE:
-        {
-               int v;
-               if (get_user(v, (int *)arg))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v));
-
-               if (v==0) {
-                       clear_bit(STATE_OVERLAY, &ztv->state);
-                       zoran_cap(ztv, 1);
-               }
-               else {
-                       /* is VIDIOCSFBUF, VIDIOCSWIN done? */
-                       if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
-                               return -EINVAL;
-
-                       set_bit(STATE_OVERLAY, &ztv->state);
-                       zoran_cap(ztv, 1);
-               }
-               break;
-        }
-
-        case VIDIOCGFBUF:
-        {
-               struct video_buffer v;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD));
-               read_lock(&ztv->lock);
-               v.base   = (void *)ztv->overinfo.busadr;
-               v.height = ztv->sheight;
-               v.width  = ztv->swidth;
-               v.depth  = ztv->depth;
-               v.bytesperline = ztv->overinfo.bpl;
-               read_unlock(&ztv->lock);
-               if(copy_to_user(arg, &v,sizeof(v)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSFBUF:
-        {
-               struct video_buffer v;
-               if(!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (pcipci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
-                       return -ENXIO;
-               if (copy_from_user(&v, arg,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
-
-               if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
-                       return -EINVAL;
-               if (v.bytesperline<1)
-                       return -EINVAL;
-               if (ztv->running)
-                       return -EBUSY;
-               write_lock_irq(&ztv->lock);
-               ztv->overinfo.busadr  = (ulong)v.base;
-               ztv->sheight      = v.height;
-               ztv->swidth       = v.width;
-               ztv->depth        = v.depth;            /* bits per pixel */
-               ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
-               ztv->overinfo.bpl = v.bytesperline;     /* bytes per line */
-               write_unlock_irq(&ztv->lock);
-               break;
-        }
-
-        case VIDIOCKEY:
-        {
-               /* Will be handled higher up .. */
-               break;
-        }
-
-        case VIDIOCSYNC:
-        {
-               int i;
-               if (get_user(i, (int *) arg))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i));
-               if (i<0 || i>ZORAN_MAX_FBUFFERS)
-                       return -EINVAL;
-               switch (ztv->grabinfo[i].status) {
-                case FBUFFER_FREE:
-                       return -EINVAL;
-                case FBUFFER_BUSY:
-                       /* wait till this buffer gets grabbed */
-                       wait_event_interruptible(ztv->grabq,
-                                       (ztv->grabinfo[i].status != FBUFFER_BUSY));
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -EINTR;
-                       /* don't fall through; a DONE buffer is not UNUSED */
-                       break;
-                case FBUFFER_DONE:
-                       ztv->grabinfo[i].status = FBUFFER_FREE;
-                       /* tell ppl we have a spare buffer */
-                       wake_up_interruptible(&ztv->grabq);
-                       break;
-               }
-               DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i));
-               break;
-        }
-
-        case VIDIOCMCAPTURE:
-        {
-               struct video_mmap vm;
-               struct vidinfo* frame;
-               if (copy_from_user(&vm,arg,sizeof(vm)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format));
-               if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
-                   vm.width<32 || vm.width>768 ||
-                   vm.height<32 || vm.height>576 ||
-                   vm.format>NRPALETTES ||
-                   palette2fmt[vm.format].mode == 0)
-                       return -EINVAL;
-
-               /* we are allowed to take over UNUSED and DONE buffers */
-               frame = &ztv->grabinfo[vm.frame];
-               if (frame->status == FBUFFER_BUSY)
-                       return -EBUSY;
-
-               /* setup the other parameters if they are given */
-               write_lock_irq(&ztv->lock);
-               frame->w = vm.width;
-               frame->h = vm.height;
-               frame->format = vm.format;
-               frame->bpp = palette2fmt[frame->format].bpp;
-               frame->bpl = frame->w*frame->bpp;
-               frame->status = FBUFFER_BUSY;
-               frame->next = 0;
-               { /* add to tail of queue */
-                 struct vidinfo* oldframe = ztv->workqueue;
-                 if (!oldframe) ztv->workqueue = frame;
-                 else {
-                   while (oldframe->next) oldframe = oldframe->next;
-                   oldframe->next = frame;
-                 }
-               }
-               write_unlock_irq(&ztv->lock);
-               zoran_cap(ztv, 1);
-               break;
-        }
-
-        case VIDIOCGMBUF:
-        {
-               struct video_mbuf mb;
-               int i;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD));
-               mb.size = ZORAN_MAX_FBUFSIZE;
-               mb.frames = ZORAN_MAX_FBUFFERS;
-               for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
-                       mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
-               if(copy_to_user(arg, &mb,sizeof(mb)))
-                       return -EFAULT;
-               break;
-        }
-
-        case VIDIOCGUNIT:
-        {
-               struct video_unit vu;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD));
-               vu.video = ztv->video_dev.minor;
-               vu.vbi = ztv->vbi_dev.minor;
-               vu.radio = VIDEO_NO_UNIT;
-               vu.audio = VIDEO_NO_UNIT;
-               vu.teletext = VIDEO_NO_UNIT;
-               if(copy_to_user(arg, &vu,sizeof(vu)))
-                       return -EFAULT;
-               break;
-        }
-
-        case VIDIOCGFREQ:
-        {
-               unsigned long v = ztv->tuner_freq;
-               if (copy_to_user(arg,&v,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD));
-               break;
-        }
-        case VIDIOCSFREQ:
-        {
-               unsigned long v;
-               if (copy_from_user(&v, arg, sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD));
-
-               if (ztv->have_tuner) {
-                       int fixme = v;
-                       if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0)
-                               return -EAGAIN;
-               }
-               ztv->tuner_freq = v;
-               break;
-        }
-
-        /* Why isn't this in the API?
-         * And why doesn't it take a buffer number?
-        case BTTV_FIELDNR:
-        {
-               unsigned long v = ztv->lastfieldnr;
-               if (copy_to_user(arg,&v,sizeof(v)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD));
-               break;
-        }
-        */
-
-        default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static
-int zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size)
-{
-       struct zoran* ztv = (struct zoran*)dev;
-       unsigned long start = (unsigned long)adr;
-       unsigned long pos;
-
-       DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size));
-
-       /* sanity checks */
-       if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer)
-               return -EINVAL;
-
-       /* start mapping the whole shabang to user memory */
-       pos = (unsigned long)ztv->fbuffer;
-       while (size>0) {
-               unsigned long pfn = virt_to_phys((void*)pos) >> PAGE_SHIFT;
-               if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       return 0;
-}
-
-static struct video_device zr36120_template=
-{
-       .owner          = THIS_MODULE,
-       .name           = "UNSET",
-       .type           = VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
-       .hardware       = VID_HARDWARE_ZR36120,
-       .open           = zoran_open,
-       .close          = zoran_close,
-       .read           = zoran_read,
-       .write          = zoran_write,
-       .poll           = zoran_poll,
-       .ioctl          = zoran_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
-       .mmap           = zoran_mmap,
-       .minor          = -1,
-};
-
-static
-int vbi_open(struct video_device *dev, int flags)
-{
-       struct zoran *ztv = dev->priv;
-       struct vidinfo* item;
-
-       DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags));
-
-       /*
-        * During VBI device open, we continiously grab VBI-like
-        * data in the vbi buffer when we have nothing to do.
-        * Only when there is an explicit request for VBI data
-        * (read call) we /force/ a read.
-        */
-
-       /* allocate buffers */
-       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
-       {
-               item->status = FBUFFER_FREE;
-
-               /* alloc */
-               if (!item->memadr) {
-                       item->memadr = bmalloc(ZORAN_VBI_BUFSIZE);
-                       if (!item->memadr) {
-                               /* could not get a buffer, bail out */
-                               while (item != ztv->readinfo) {
-                                       item--;
-                                       bfree(item->memadr, ZORAN_VBI_BUFSIZE);
-                                       item->memadr = 0;
-                                       item->busadr = 0;
-                               }
-                               return -ENOBUFS;
-                       }
-               }
-
-               /* determine the DMAable address */
-               item->busadr = virt_to_bus(item->memadr);
-       }
-
-       /* do the common part of all open's */
-       zoran_common_open(ztv, flags);
-
-       set_bit(STATE_VBI, &ztv->state);
-       /* start read-ahead */
-       zoran_cap(ztv, 1);
-
-       return 0;
-}
-
-static
-void vbi_close(struct video_device *dev)
-{
-       struct zoran *ztv = dev->priv;
-       struct vidinfo* item;
-
-       DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD));
-
-       /* driver specific closure */
-       clear_bit(STATE_VBI, &ztv->state);
-
-       zoran_common_close(ztv);
-
-       /*
-        *      This is sucky but right now I can't find a good way to
-        *      be sure its safe to free the buffer. We wait 5-6 fields
-        *      which is more than sufficient to be sure.
-        */
-       msleep(100);                    /* Wait 1/10th of a second */
-
-       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
-       {
-               if (item->memadr)
-                       bfree(item->memadr, ZORAN_VBI_BUFSIZE);
-               item->memadr = 0;
-       }
-
-}
-
-/*
- * This read function could be used reentrant in a SMP situation.
- *
- * This is made possible by the spinlock which is kept till we
- * found and marked a buffer for our own use. The lock must
- * be released as soon as possible to prevent lock contention.
- */
-static
-long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
-{
-       struct zoran *ztv = dev->priv;
-       unsigned long max;
-       struct vidinfo* unused = 0;
-       struct vidinfo* done = 0;
-
-       DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock));
-
-       /* find ourself a free or completed buffer */
-       for (;;) {
-               struct vidinfo* item;
-
-               write_lock_irq(&ztv->lock);
-               for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) {
-                       if (!unused && item->status == FBUFFER_FREE)
-                               unused = item;
-                       if (!done && item->status == FBUFFER_DONE)
-                               done = item;
-               }
-               if (done || unused)
-                       break;
-
-               /* no more free buffers, wait for them. */
-               write_unlock_irq(&ztv->lock);
-               if (nonblock)
-                       return -EWOULDBLOCK;
-               interruptible_sleep_on(&ztv->vbiq);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       /* Do we have 'ready' data? */
-       if (!done) {
-               /* no? than this will take a while... */
-               if (nonblock) {
-                       write_unlock_irq(&ztv->lock);
-                       return -EWOULDBLOCK;
-               }
-
-               /* mark the unused buffer as wanted */
-               unused->status = FBUFFER_BUSY;
-               unused->next = 0;
-               { /* add to tail of queue */
-                 struct vidinfo* oldframe = ztv->workqueue;
-                 if (!oldframe) ztv->workqueue = unused;
-                 else {
-                   while (oldframe->next) oldframe = oldframe->next;
-                   oldframe->next = unused;
-                 }
-               }
-               write_unlock_irq(&ztv->lock);
-
-               /* tell the state machine we want it filled /NOW/ */
-               zoran_cap(ztv, 1);
-
-               /* wait till this buffer gets grabbed */
-               wait_event_interruptible(ztv->vbiq,
-                               (unused->status != FBUFFER_BUSY));
-               /* see if a signal did it */
-               if (signal_pending(current))
-                       return -EINTR;
-               done = unused;
-       }
-       else
-               write_unlock_irq(&ztv->lock);
-
-       /* Yes! we got data! */
-       max = done->bpl * -done->h;
-       if (count > max)
-               count = max;
-
-       /* check if the user gave us enough room to write the data */
-       if (!access_ok(VERIFY_WRITE, buf, count)) {
-               count = -EFAULT;
-               goto out;
-       }
-
-       /*
-        * Now transform/strip the data from YUV to Y-only
-        * NB. Assume the Y is in the LSB of the YUV data.
-        */
-       {
-       unsigned char* optr = buf;
-       unsigned char* eptr = buf+count;
-
-       /* are we beeing accessed from an old driver? */
-       if (count == 2*19*2048) {
-               /*
-                * Extreme HACK, old VBI programs expect 2048 points
-                * of data, and we only got 864 orso. Double each
-                * datapoint and clear the rest of the line.
-                * This way we have appear to have a
-                * sample_frequency of 29.5 Mc.
-                */
-               int x,y;
-               unsigned char* iptr = done->memadr+1;
-               for (y=done->h; optr<eptr && y<0; y++)
-               {
-                       /* copy to doubled data to userland */
-                       for (x=0; optr+1<eptr && x<-done->w; x++)
-                       {
-                               unsigned char a = iptr[x*2];
-                               __put_user(a, optr++);
-                               __put_user(a, optr++);
-                       }
-                       /* and clear the rest of the line */
-                       for (x*=2; optr<eptr && x<done->bpl; x++)
-                               __put_user(0, optr++);
-                       /* next line */
-                       iptr += done->bpl;
-               }
-       }
-       else {
-               /*
-                * Other (probably newer) programs asked
-                * us what geometry we are using, and are
-                * reading the correct size.
-                */
-               int x,y;
-               unsigned char* iptr = done->memadr+1;
-               for (y=done->h; optr<eptr && y<0; y++)
-               {
-                       /* copy to doubled data to userland */
-                       for (x=0; optr<eptr && x<-done->w; x++)
-                               __put_user(iptr[x*2], optr++);
-                       /* and clear the rest of the line */
-                       for (;optr<eptr && x<done->bpl; x++)
-                               __put_user(0, optr++);
-                       /* next line */
-                       iptr += done->bpl;
-               }
-       }
-
-       /* API compliance:
-        * place the framenumber (half fieldnr) in the last long
-        */
-       __put_user(done->fieldnr/2, ((ulong*)eptr)[-1]);
-       }
-
-       /* keep the engine running */
-       done->status = FBUFFER_FREE;
-       zoran_cap(ztv, 1);
-
-       /* tell listeners this buffer just became free */
-       wake_up_interruptible(&ztv->vbiq);
-
-       /* goodbye */
-out:
-       DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count));
-       return count;
-}
-
-static
-unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait)
-{
-       struct zoran *ztv = dev->priv;
-       struct vidinfo* item;
-       unsigned int mask = 0;
-
-       poll_wait(file, &ztv->vbiq, wait);
-
-       for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
-               if (item->status == FBUFFER_DONE)
-               {
-                       mask |= (POLLIN | POLLRDNORM);
-                       break;
-               }
-
-       DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask));
-
-       return mask;
-}
-
-static
-int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-       struct zoran* ztv = dev->priv;
-
-       switch (cmd) {
-        case VIDIOCGVBIFMT:
-        {
-               struct vbi_format f;
-               DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD));
-               f.sampling_rate = 14750000UL;
-               f.samples_per_line = -ztv->readinfo[0].w;
-               f.sample_format = VIDEO_PALETTE_RAW;
-               f.start[0] = f.start[1] = ztv->readinfo[0].y;
-               f.start[1] += 312;
-               f.count[0] = f.count[1] = -ztv->readinfo[0].h;
-               f.flags = VBI_INTERLACED;
-               if (copy_to_user(arg,&f,sizeof(f)))
-                       return -EFAULT;
-               break;
-        }
-        case VIDIOCSVBIFMT:
-        {
-               struct vbi_format f;
-               int i;
-               if (copy_from_user(&f, arg,sizeof(f)))
-                       return -EFAULT;
-               DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags));
-
-               /* lots of parameters are fixed... (PAL) */
-               if (f.sampling_rate != 14750000UL ||
-                   f.samples_per_line > 864 ||
-                   f.sample_format != VIDEO_PALETTE_RAW ||
-                   f.start[0] < 0 ||
-                   f.start[0] != f.start[1]-312 ||
-                   f.count[0] != f.count[1] ||
-                   f.start[0]+f.count[0] >= 288 ||
-                   f.flags != VBI_INTERLACED)
-                       return -EINVAL;
-
-               write_lock_irq(&ztv->lock);
-               ztv->readinfo[0].y = f.start[0];
-               ztv->readinfo[0].w = -f.samples_per_line;
-               ztv->readinfo[0].h = -f.count[0];
-               ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp;
-               for (i=1; i<ZORAN_VBI_BUFFERS; i++)
-                       ztv->readinfo[i] = ztv->readinfo[i];
-               write_unlock_irq(&ztv->lock);
-               break;
-        }
-        default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static struct video_device vbi_template=
-{
-       .owner          = THIS_MODULE,
-       .name           = "UNSET",
-       .type           = VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
-       .hardware       = VID_HARDWARE_ZR36120,
-       .open           = vbi_open,
-       .close          = vbi_close,
-       .read           = vbi_read,
-       .write          = zoran_write,
-       .poll           = vbi_poll,
-       .ioctl          = vbi_ioctl,
-       .minor          = -1,
-};
-
-/*
- *      Scan for a Zoran chip, request the irq and map the io memory
- */
-static
-int __init find_zoran(void)
-{
-       int result;
-       struct zoran *ztv;
-       struct pci_dev *dev = NULL;
-       unsigned char revision;
-       int zoran_num = 0;
-
-       while ((dev = pci_get_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
-       {
-               /* Ok, a ZR36120/ZR36125 found! */
-               ztv = &zorans[zoran_num];
-               ztv->dev = dev;
-
-               if (pci_enable_device(dev))
-                       continue;
-
-               pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
-               printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
-                       dev->device, revision);
-               printk("bus: %d, devfn: %d, irq: %d, ",
-                       dev->bus->number, dev->devfn, dev->irq);
-               printk("memory: 0x%08lx.\n", ztv->zoran_adr);
-
-               ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
-               DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
-
-               result = request_irq(dev->irq, zoran_irq,
-                       IRQF_SHARED|IRQF_DISABLED,"zoran", ztv);
-               if (result==-EINVAL)
-               {
-                       iounmap(ztv->zoran_mem);
-                       printk(KERN_ERR "zoran: Bad irq number or handler\n");
-                       continue;
-               }
-               if (result==-EBUSY)
-                       printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq);
-               if (result < 0) {
-                       iounmap(ztv->zoran_mem);
-                       continue;
-               }
-               /* Enable bus-mastering */
-               pci_set_master(dev);
-               /* Keep a reference */
-               pci_dev_get(dev);
-               zoran_num++;
-       }
-       if(zoran_num)
-               printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
-       return zoran_num;
-}
-
-static
-int __init init_zoran(int card)
-{
-       struct zoran *ztv = &zorans[card];
-       int     i;
-
-       /* if the given cardtype valid? */
-       if (cardtype[card]>=NRTVCARDS) {
-               printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]);
-               return -1;
-       }
-
-       /* reset the zoran */
-       zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
-       udelay(10);
-       zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
-       udelay(10);
-
-       /* zoran chip specific details */
-       ztv->card = tvcards+cardtype[card];     /* point to the selected card */
-       ztv->norm = 0;                          /* PAL */
-       ztv->tuner_freq = 0;
-
-       /* videocard details */
-       ztv->swidth = 800;
-       ztv->sheight = 600;
-       ztv->depth = 16;
-
-       /* State details */
-       ztv->fbuffer = 0;
-       ztv->overinfo.kindof = FBUFFER_OVERLAY;
-       ztv->overinfo.status = FBUFFER_FREE;
-       ztv->overinfo.x = 0;
-       ztv->overinfo.y = 0;
-       ztv->overinfo.w = 768; /* 640 */
-       ztv->overinfo.h = 576; /* 480 */
-       ztv->overinfo.format = VIDEO_PALETTE_RGB565;
-       ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp;
-       ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth;
-       ztv->overinfo.busadr = 0;
-       ztv->overinfo.memadr = 0;
-       ztv->overinfo.overlay = 0;
-       for (i=0; i<ZORAN_MAX_FBUFFERS; i++) {
-               ztv->grabinfo[i] = ztv->overinfo;
-               ztv->grabinfo[i].kindof = FBUFFER_GRAB;
-       }
-       init_waitqueue_head(&ztv->grabq);
-
-       /* VBI details */
-       ztv->readinfo[0] = ztv->overinfo;
-       ztv->readinfo[0].kindof = FBUFFER_VBI;
-       ztv->readinfo[0].w = -864;
-       ztv->readinfo[0].h = -38;
-       ztv->readinfo[0].format = VIDEO_PALETTE_YUV422;
-       ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp;
-       ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp;
-       for (i=1; i<ZORAN_VBI_BUFFERS; i++)
-               ztv->readinfo[i] = ztv->readinfo[0];
-       init_waitqueue_head(&ztv->vbiq);
-
-       /* maintenance data */
-       ztv->have_decoder = 0;
-       ztv->have_tuner = 0;
-       ztv->tuner_type = 0;
-       ztv->running = 0;
-       ztv->users = 0;
-       rwlock_init(&ztv->lock);
-       ztv->workqueue = 0;
-       ztv->fieldnr = 0;
-       ztv->lastfieldnr = 0;
-
-       if (triton1)
-               zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
-
-       /* external FL determines TOP frame */
-       zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC);
-
-       /* set HSpol */
-       if (ztv->card->hsync_pos)
-               zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH);
-       /* set VSpol */
-       if (ztv->card->vsync_pos)
-               zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV);
-
-       /* Set the proper General Purpuse register bits */
-       /* implicit: no softreset, 0 waitstates */
-       zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI);
-       /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
-       zrwrite(ztv->card->gpval<<24,ZORAN_GUEST);
-
-       /* clear interrupt status */
-       zrwrite(~0, ZORAN_ISR);
-
-       /*
-        * i2c template
-        */
-       ztv->i2c = zoran_i2c_bus_template;
-       sprintf(ztv->i2c.name,"zoran-%d",card);
-       ztv->i2c.data = ztv;
-
-       /*
-        * Now add the template and register the device unit
-        */
-       ztv->video_dev = zr36120_template;
-       strcpy(ztv->video_dev.name, ztv->i2c.name);
-       ztv->video_dev.priv = ztv;
-       if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0)
-               return -1;
-
-       ztv->vbi_dev = vbi_template;
-       strcpy(ztv->vbi_dev.name, ztv->i2c.name);
-       ztv->vbi_dev.priv = ztv;
-       if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) {
-               video_unregister_device(&ztv->video_dev);
-               return -1;
-       }
-       i2c_register_bus(&ztv->i2c);
-
-       /* set interrupt mask - the PIN enable will be set later */
-       zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR);
-
-       printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name);
-       return 0;
-}
-
-static
-void release_zoran(int max)
-{
-       struct zoran *ztv;
-       int i;
-
-       for (i=0;i<max; i++)
-       {
-               ztv = &zorans[i];
-
-               /* turn off all capturing, DMA and IRQs */
-               /* reset the zoran */
-               zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
-               udelay(10);
-               zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
-               udelay(10);
-
-               /* first disable interrupts before unmapping the memory! */
-               zrwrite(0, ZORAN_ICR);
-               zrwrite(0xffffffffUL,ZORAN_ISR);
-
-               /* free it */
-               free_irq(ztv->dev->irq,ztv);
-
-               /* unregister i2c_bus */
-               i2c_unregister_bus((&ztv->i2c));
-
-               /* unmap and free memory */
-               if (ztv->zoran_mem)
-                       iounmap(ztv->zoran_mem);
-
-               /* Drop PCI device */
-               pci_dev_put(ztv->dev);
-
-               video_unregister_device(&ztv->video_dev);
-               video_unregister_device(&ztv->vbi_dev);
-       }
-}
-
-void __exit zr36120_exit(void)
-{
-       release_zoran(zoran_cards);
-}
-
-int __init zr36120_init(void)
-{
-       int     card;
-
-       handle_chipset();
-       zoran_cards = find_zoran();
-       if (zoran_cards <= 0)
-               return -EIO;
-
-       /* initialize Zorans */
-       for (card=0; card<zoran_cards; card++) {
-               if (init_zoran(card) < 0) {
-                       /* only release the zorans we have registered */
-                       release_zoran(card);
-                       return -EIO;
-               }
-       }
-       return 0;
-}
-
-module_init(zr36120_init);
-module_exit(zr36120_exit);
diff --git a/drivers/media/video/zr36120.h b/drivers/media/video/zr36120.h
deleted file mode 100644 (file)
index a71e485..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
-    zr36120.h - Zoran 36120/36125 based framegrabbers
-
-    Copyright (C) 1998-1999 Pauline Middelink (middelin@polyware.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 _ZR36120_H
-#define _ZR36120_H
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#include <linux/i2c-old.h>
-#include <linux/videodev.h>
-
-#include <asm/io.h>
-
-/*
- * Debug macro's, place an x behind the ) for actual debug-compilation
- * E.g. #define DEBUG(x...)    x
- */
-#define DEBUG(x...)                    /* Debug driver */
-#define IDEBUG(x...)                   /* Debug interrupt handler */
-#define PDEBUG         0               /* Debug PCI writes */
-
-/* defined in zr36120_i2c */
-extern struct i2c_bus zoran_i2c_bus_template;
-
-#define        ZORAN_MAX_FBUFFERS      2
-#define        ZORAN_MAX_FBUFFER       (768*576*2)
-#define        ZORAN_MAX_FBUFSIZE      (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
-
-#define        ZORAN_VBI_BUFFERS       2
-#define        ZORAN_VBI_BUFSIZE       (22*1024*2)
-
-struct tvcard {
-       char*   name;           /* name of the cardtype */
-       int     video_inputs;   /* number of channels defined in video_mux */
-       int     audio_inputs;   /* number of channels defined in audio_mux */
-       __u32   swapi2c:1,      /* need to swap i2c wires SDA/SCL? */
-               usegirq1:1,     /* VSYNC at GIRQ1 instead of GIRQ0? */
-               vsync_pos:1,    /* positive VSYNC signal? */
-               hsync_pos:1,    /* positive HSYNC signal? */
-               gpdir:8,        /* General Purpose Direction register */
-               gpval:8;        /* General Purpose Value register */
-       int     video_mux[6];   /* mapping channel number to physical input */
-#define                IS_TUNER        0x80
-#define                IS_SVHS         0x40
-#define                CHANNEL_MASK    0x3F
-       int     audio_mux[6];   /* mapping channel number to physical input */
-};
-#define        TUNER(x)        ((x)|IS_TUNER)
-#define        SVHS(x)         ((x)|IS_SVHS)
-
-struct vidinfo {
-       struct  vidinfo* next;  /* next active buffer                   */
-       uint    kindof;
-#define        FBUFFER_OVERLAY         0
-#define        FBUFFER_GRAB            1
-#define        FBUFFER_VBI             2
-       uint    status;
-#define FBUFFER_FREE           0
-#define FBUFFER_BUSY           1
-#define FBUFFER_DONE           2
-       ulong   fieldnr;        /* # of field, not framer!              */
-       uint    x,y;
-       int     w,h;            /* w,h can be negative!                 */
-       uint    format;         /* index in palette2fmt[]               */
-       uint    bpp;            /* lookup from palette2fmt[]            */
-       uint    bpl;            /* calc: width * bpp                    */
-       ulong   busadr;         /* bus addr for DMA engine              */
-       char*   memadr;         /* kernel addr for making copies        */
-       ulong*  overlay;        /* kernel addr of overlay mask          */
-};
-
-struct zoran
-{
-       struct video_device video_dev;
-#define CARD_DEBUG     KERN_DEBUG "%s(%lu): "
-#define CARD_INFO      KERN_INFO "%s(%lu): "
-#define CARD_ERR       KERN_ERR "%s(%lu): "
-#define CARD           ztv->video_dev.name,ztv->fieldnr
-
-       /* zoran chip specific details */
-       struct i2c_bus  i2c;            /* i2c registration data        */
-       struct pci_dev* dev;            /* ptr to PCI device            */
-       ulong           zoran_adr;      /* bus address of IO memory     */
-       char*           zoran_mem;      /* kernel address of IO memory  */
-       struct tvcard*  card;           /* the cardtype                 */
-       uint            norm;           /* 0=PAL, 1=NTSC, 2=SECAM       */
-       uint            tuner_freq;     /* Current freq in kHz          */
-       struct video_picture picture;   /* Current picture params       */
-
-       /* videocard details */
-       uint            swidth;         /* screen width                 */
-       uint            sheight;        /* screen height                */
-       uint            depth;          /* depth in bits                */
-
-       /* State details */
-       char*           fbuffer;        /* framebuffers for mmap        */
-       struct vidinfo  overinfo;       /* overlay data                 */
-       struct vidinfo  grabinfo[ZORAN_MAX_FBUFFERS];   /* grabbing data*/
-       wait_queue_head_t grabq;        /* grabbers queue               */
-
-       /* VBI details */
-       struct video_device vbi_dev;
-       struct vidinfo  readinfo[2];    /* VBI data - flip buffers      */
-       wait_queue_head_t vbiq;         /* vbi queue                    */
-
-       /* maintenance data */
-       int             have_decoder;   /* did we detect a mux?         */
-       int             have_tuner;     /* did we detect a tuner?       */
-       int             users;          /* howmany video/vbi open?      */
-       int             tuner_type;     /* tuner type, when found       */
-       int             running;        /* are we rolling?              */
-       rwlock_t        lock;
-       long            state;          /* what is requested of us?     */
-#define STATE_OVERLAY  0
-#define STATE_VBI      1
-       struct vidinfo* workqueue;      /* buffers to grab, head is active */
-       ulong           fieldnr;        /* #field, ticked every VSYNC   */
-       ulong           lastfieldnr;    /* #field, ticked every GRAB    */
-
-       int             vidInterlace;   /* calculated */
-       int             vidXshift;      /* calculated */
-       uint            vidWidth;       /* calculated */
-       uint            vidHeight;      /* calculated */
-};
-
-#define zrwrite(dat,adr)    writel((dat),(char *) (ztv->zoran_mem+(adr)))
-#define zrread(adr)         readl(ztv->zoran_mem+(adr))
-
-#if PDEBUG == 0
-#define zrand(dat,adr)      zrwrite((dat) & zrread(adr), adr)
-#define zror(dat,adr)       zrwrite((dat) | zrread(adr), adr)
-#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr)
-#else
-#define zrand(dat, adr) \
-do { \
-       ulong data = (dat) & zrread((adr)); \
-       zrwrite(data, (adr)); \
-       if (0 != (~(dat) & zrread((adr)))) \
-               printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \
-} while(0)
-
-#define zror(dat, adr) \
-do { \
-       ulong data = (dat) | zrread((adr)); \
-       zrwrite(data, (adr)); \
-       if ((dat) != ((dat) & zrread(adr))) \
-               printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \
-} while(0)
-
-#define zraor(dat, mask, adr) \
-do { \
-       ulong data; \
-       if ((dat) & (mask)) \
-               printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
-       data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \
-       zrwrite(data,(adr)); \
-       if ( (dat) != (~(mask) & zrread((adr))) ) \
-               printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \
-} while(0)
-#endif
-
-#endif
-
-/* zoran PCI address space */
-#define ZORAN_VFEH             0x000   /* Video Front End Horizontal Conf. */
-#define        ZORAN_VFEH_HSPOL        (1<<30)
-#define        ZORAN_VFEH_HSTART       (0x3FF<<10)
-#define        ZORAN_VFEH_HEND         (0x3FF<<0)
-
-#define ZORAN_VFEV             0x004   /* Video Front End Vertical Conf. */
-#define        ZORAN_VFEV_VSPOL        (1<<30)
-#define        ZORAN_VFEV_VSTART       (0x3FF<<10)
-#define        ZORAN_VFEV_VEND         (0x3FF<<0)
-
-#define        ZORAN_VFEC              0x008   /* Video Front End Scaler and Pixel */
-#define ZORAN_VFEC_EXTFL       (1<<26)
-#define        ZORAN_VFEC_TOPFIELD     (1<<25)
-#define        ZORAN_VFEC_VCLKPOL      (1<<24)
-#define        ZORAN_VFEC_HFILTER      (7<<21)
-#define        ZORAN_VFEC_HFILTER_1    (0<<21) /* no lumi,    3-tap chromo */
-#define        ZORAN_VFEC_HFILTER_2    (1<<21) /* 3-tap lumi, 3-tap chromo */
-#define        ZORAN_VFEC_HFILTER_3    (2<<21) /* 4-tap lumi, 4-tap chromo */
-#define        ZORAN_VFEC_HFILTER_4    (3<<21) /* 5-tap lumi, 4-tap chromo */
-#define        ZORAN_VFEC_HFILTER_5    (4<<21) /* 4-tap lumi, 4-tap chromo */
-#define        ZORAN_VFEC_DUPFLD       (1<<20)
-#define        ZORAN_VFEC_HORDCM       (63<<14)
-#define        ZORAN_VFEC_VERDCM       (63<<8)
-#define        ZORAN_VFEC_DISPMOD      (1<<6)
-#define        ZORAN_VFEC_RGB          (3<<3)
-#define        ZORAN_VFEC_RGB_YUV422   (0<<3)
-#define        ZORAN_VFEC_RGB_RGB888   (1<<3)
-#define        ZORAN_VFEC_RGB_RGB565   (2<<3)
-#define        ZORAN_VFEC_RGB_RGB555   (3<<3)
-#define        ZORAN_VFEC_ERRDIF       (1<<2)
-#define        ZORAN_VFEC_PACK24       (1<<1)
-#define        ZORAN_VFEC_LE           (1<<0)
-
-#define        ZORAN_VTOP              0x00C   /* Video Display "Top" */
-
-#define        ZORAN_VBOT              0x010   /* Video Display "Bottom" */
-
-#define        ZORAN_VSTR              0x014   /* Video Display Stride */
-#define        ZORAN_VSTR_DISPSTRIDE   (0xFFFF<<16)
-#define        ZORAN_VSTR_VIDOVF       (1<<8)
-#define        ZORAN_VSTR_SNAPSHOT     (1<<1)
-#define        ZORAN_VSTR_GRAB         (1<<0)
-
-#define        ZORAN_VDC               0x018   /* Video Display Conf. */
-#define        ZORAN_VDC_VIDEN         (1<<31)
-#define        ZORAN_VDC_MINPIX        (0x1F<<25)
-#define        ZORAN_VDC_TRICOM        (1<<24)
-#define        ZORAN_VDC_VIDWINHT      (0x3FF<<12)
-#define        ZORAN_VDC_VIDWINWID     (0x3FF<<0)
-
-#define        ZORAN_MTOP              0x01C   /* Masking Map "Top" */
-
-#define        ZORAN_MBOT              0x020   /* Masking Map "Bottom" */
-
-#define        ZORAN_OCR               0x024   /* Overlay Control */
-#define        ZORAN_OCR_OVLEN         (1<<15)
-#define        ZORAN_OCR_MASKSTRIDE    (0xFF<<0)
-
-#define        ZORAN_PCI               0x028   /* System, PCI and GPP Control */
-#define        ZORAN_PCI_SOFTRESET     (1<<24)
-#define        ZORAN_PCI_WAITSTATE     (3<<16)
-#define        ZORAN_PCI_GENPURDIR     (0xFF<<0)
-
-#define        ZORAN_GUEST             0x02C   /* GuestBus Control */
-
-#define        ZORAN_CSOURCE           0x030   /* Code Source Address */
-
-#define        ZORAN_CTRANS            0x034   /* Code Transfer Control */
-
-#define        ZORAN_CMEM              0x038   /* Code Memory Pointer */
-
-#define        ZORAN_ISR               0x03C   /* Interrupt Status Register */
-#define        ZORAN_ISR_CODE          (1<<28)
-#define        ZORAN_ISR_GIRQ0         (1<<29)
-#define        ZORAN_ISR_GIRQ1         (1<<30)
-
-#define        ZORAN_ICR               0x040   /* Interrupt Control Register */
-#define        ZORAN_ICR_EN            (1<<24)
-#define        ZORAN_ICR_CODE          (1<<28)
-#define        ZORAN_ICR_GIRQ0         (1<<29)
-#define        ZORAN_ICR_GIRQ1         (1<<30)
-
-#define        ZORAN_I2C               0x044   /* I2C-Bus */
-#define ZORAN_I2C_SCL          (1<<1)
-#define ZORAN_I2C_SDA          (1<<0)
-
-#define        ZORAN_POST              0x48    /* PostOffice */
-#define        ZORAN_POST_PEN          (1<<25)
-#define        ZORAN_POST_TIME         (1<<24)
-#define        ZORAN_POST_DIR          (1<<23)
-#define        ZORAN_POST_GUESTID      (3<<20)
-#define        ZORAN_POST_GUEST        (7<<16)
-#define        ZORAN_POST_DATA         (0xFF<<0)
-
-#endif
diff --git a/drivers/media/video/zr36120_i2c.c b/drivers/media/video/zr36120_i2c.c
deleted file mode 100644 (file)
index 21fde43..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
-    zr36120_i2c.c - Zoran 36120/36125 based framegrabbers
-
-    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.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.
-*/
-
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-#include <linux/video_decoder.h>
-#include <asm/uaccess.h>
-
-#include "tuner.h"
-#include "zr36120.h"
-
-/* ----------------------------------------------------------------------- */
-/* I2C functions                                                          */
-/* ----------------------------------------------------------------------- */
-
-/* software I2C functions */
-
-#define I2C_DELAY   10
-
-static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
-{
-       struct zoran *ztv = (struct zoran*)bus->data;
-       unsigned int b = 0;
-       if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA;
-       if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL;
-       zrwrite(b, ZORAN_I2C);
-       udelay(I2C_DELAY);
-}
-
-static int i2c_getdataline(struct i2c_bus *bus)
-{
-       struct zoran *ztv = (struct zoran*)bus->data;
-       if (ztv->card->swapi2c)
-               return zrread(ZORAN_I2C) & ZORAN_I2C_SCL;
-       return zrread(ZORAN_I2C) & ZORAN_I2C_SDA;
-}
-
-static
-void attach_inform(struct i2c_bus *bus, int id)
-{
-       struct zoran *ztv = (struct zoran*)bus->data;
-       struct video_decoder_capability dc;
-       int rv;
-
-       switch (id) {
-        case I2C_DRIVERID_VIDEODECODER:
-               DEBUG(printk(CARD_INFO "decoder attached\n",CARD));
-
-               /* fetch the capabilities of the decoder */
-               rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
-               if (rv) {
-                       DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD));
-                       break;
-               }
-               DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
-
-               /* Test if the decoder can de VBI transfers */
-               if (dc.flags & 16 /*VIDEO_DECODER_VBI*/)
-                       ztv->have_decoder = 2;
-               else
-                       ztv->have_decoder = 1;
-               break;
-        case I2C_DRIVERID_TUNER:
-               ztv->have_tuner = 1;
-               DEBUG(printk(CARD_INFO "tuner attached\n",CARD));
-               if (ztv->tuner_type >= 0)
-               {
-                       if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0)
-                       DEBUG(printk(CARD_INFO "attach_inform; tuner won't be set to type %d\n",CARD,ztv->tuner_type));
-               }
-               break;
-        default:
-               DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id));
-               break;
-       }
-}
-
-static
-void detach_inform(struct i2c_bus *bus, int id)
-{
-       struct zoran *ztv = (struct zoran*)bus->data;
-
-       switch (id) {
-        case I2C_DRIVERID_VIDEODECODER:
-               ztv->have_decoder = 0;
-               DEBUG(printk(CARD_INFO "decoder detached\n",CARD));
-               break;
-        case I2C_DRIVERID_TUNER:
-               ztv->have_tuner = 0;
-               DEBUG(printk(CARD_INFO "tuner detached\n",CARD));
-               break;
-        default:
-               DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id));
-               break;
-       }
-}
-
-struct i2c_bus zoran_i2c_bus_template =
-{
-       "ZR36120",
-       I2C_BUSID_ZORAN,
-       NULL,
-
-       SPIN_LOCK_UNLOCKED,
-
-       attach_inform,
-       detach_inform,
-
-       i2c_setlines,
-       i2c_getdataline,
-       NULL,
-       NULL
-};
diff --git a/drivers/media/video/zr36120_mem.c b/drivers/media/video/zr36120_mem.c
deleted file mode 100644 (file)
index 416eaa9..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-    zr36120_mem.c - Zoran 36120/36125 based framegrabbers
-
-    Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.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.
-*/
-
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <asm/io.h>
-#ifdef CONFIG_BIGPHYS_AREA
-#include <linux/bigphysarea.h>
-#endif
-
-#include "zr36120.h"
-#include "zr36120_mem.h"
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-void* bmalloc(unsigned long size)
-{
-       void* mem;
-#ifdef CONFIG_BIGPHYS_AREA
-       mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL);
-#else
-       /*
-        * The following function got a lot of memory at boottime,
-        * so we know its always there...
-        */
-       mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
-#endif
-       if (mem) {
-               unsigned long adr = (unsigned long)mem;
-               while (size > 0) {
-                       SetPageReserved(virt_to_page(phys_to_virt(adr)));
-                       adr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-       return mem;
-}
-
-void bfree(void* mem, unsigned long size)
-{
-       if (mem) {
-               unsigned long adr = (unsigned long)mem;
-               unsigned long siz = size;
-               while (siz > 0) {
-                       ClearPageReserved(virt_to_page(phys_to_virt(adr)));
-                       adr += PAGE_SIZE;
-                       siz -= PAGE_SIZE;
-               }
-#ifdef CONFIG_BIGPHYS_AREA
-               bigphysarea_free_pages(mem);
-#else
-               free_pages((unsigned long)mem,get_order(size));
-#endif
-       }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zr36120_mem.h b/drivers/media/video/zr36120_mem.h
deleted file mode 100644 (file)
index aad117a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* either kmalloc() or bigphysarea() alloced memory - continuous */
-void*  bmalloc(unsigned long size);
-void   bfree(void* mem, unsigned long size);
index 4633dbc9a90fe38f9f7883ba66c3ce2e0990c1f5..08a33c33f6edbb98ddd1dbd044f4f3848123bde4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver
+ *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
  *
  *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
  *
@@ -11,7 +11,7 @@
  */
 
 /*
-   This is the AT91RM9200 MCI driver that has been tested with both MMC cards
+   This is the AT91 MCI driver that has been tested with both MMC cards
    and SD-cards.  Boards that support write protect are now supported.
    The CCAT91SBC001 board does not support SD cards.
 
@@ -38,8 +38,8 @@
      controller to manage the transfers.
 
      A read is done from the controller directly to the scatterlist passed in from the request.
-     Due to a bug in the controller, when a read is completed, all the words are byte
-     swapped in the scatterlist buffers.
+     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
+     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
 
      The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
 
@@ -72,6 +72,7 @@
 #include <asm/irq.h>
 #include <asm/mach/mmc.h>
 #include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/at91_mci.h>
 #include <asm/arch/at91_pdc.h>
 
 #undef SUPPORT_4WIRE
 
-static struct clk *mci_clk;
+#define FL_SENT_COMMAND        (1 << 0)
+#define FL_SENT_STOP   (1 << 1)
 
-#define FL_SENT_COMMAND (1 << 0)
-#define FL_SENT_STOP (1 << 1)
+#define AT91_MCI_ERRORS        (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE       \
+               | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE               \
+               | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)                        
 
+#define at91_mci_read(host, reg)       __raw_readl((host)->baseaddr + (reg))
+#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
 
 
-/*
- * Read from a MCI register.
- */
-static inline unsigned long at91_mci_read(unsigned int reg)
-{
-       void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
-
-       return __raw_readl(mci_base + reg);
-}
-
-/*
- * Write to a MCI register.
- */
-static inline void at91_mci_write(unsigned int reg, unsigned long value)
-{
-        void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
-
-        __raw_writel(value, mci_base + reg);
-}
-
 /*
  * Low level type for this driver
  */
@@ -116,9 +101,14 @@ struct at91mci_host
        struct mmc_command *cmd;
        struct mmc_request *request;
 
+       void __iomem *baseaddr;
+       int irq;
+
        struct at91_mmc_data *board;
        int present;
 
+       struct clk *mci_clk;
+
        /*
         * Flag indicating when the command has been sent. This is used to
         * work out whether or not to send the stop
@@ -158,7 +148,6 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
        for (i = 0; i < len; i++) {
                struct scatterlist *sg;
                int amount;
-               int index;
                unsigned int *sgbuffer;
 
                sg = &data->sg[i];
@@ -166,10 +155,15 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
                sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
-               amount /= 4;
 
-               for (index = 0; index < amount; index++)
-                       *dmabuf++ = swab32(sgbuffer[index]);
+               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
+                       int index;
+
+                       for (index = 0; index < (amount / 4); index++)
+                               *dmabuf++ = swab32(sgbuffer[index]);
+               }
+               else
+                       memcpy(dmabuf, sgbuffer, amount);
 
                kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
 
@@ -217,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
 
                /* Check to see if this needs filling */
                if (i == 0) {
-                       if (at91_mci_read(AT91_PDC_RCR) != 0) {
+                       if (at91_mci_read(host, AT91_PDC_RCR) != 0) {
                                pr_debug("Transfer active in current\n");
                                continue;
                        }
                }
                else {
-                       if (at91_mci_read(AT91_PDC_RNCR) != 0) {
+                       if (at91_mci_read(host, AT91_PDC_RNCR) != 0) {
                                pr_debug("Transfer active in next\n");
                                continue;
                        }
@@ -240,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
                pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
 
                if (i == 0) {
-                       at91_mci_write(AT91_PDC_RPR, sg->dma_address);
-                       at91_mci_write(AT91_PDC_RCR, sg->length / 4);
+                       at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
+                       at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
                }
                else {
-                       at91_mci_write(AT91_PDC_RNPR, sg->dma_address);
-                       at91_mci_write(AT91_PDC_RNCR, sg->length / 4);
+                       at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
+                       at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
                }
        }
 
@@ -276,8 +270,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
 
        while (host->in_use_index < host->transfer_index) {
                unsigned int *buffer;
-               int index;
-               int len;
 
                struct scatterlist *sg;
 
@@ -295,11 +287,13 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
 
                data->bytes_xfered += sg->length;
 
-               len = sg->length / 4;
+               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
+                       int index;
 
-               for (index = 0; index < len; index++) {
-                       buffer[index] = swab32(buffer[index]);
+                       for (index = 0; index < (sg->length / 4); index++)
+                               buffer[index] = swab32(buffer[index]);
                }
+
                kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
                flush_dcache_page(sg->page);
        }
@@ -308,8 +302,8 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
        if (host->transfer_index < data->sg_len)
                at91mci_pre_dma_read(host);
        else {
-               at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF);
-               at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
+               at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
        }
 
        pr_debug("post dma read done\n");
@@ -326,11 +320,11 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
        pr_debug("Handling the transmit\n");
 
        /* Disable the transfer */
-       at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+       at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
 
        /* Now wait for cmd ready */
-       at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE);
-       at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY);
+       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
+       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
 
        cmd = host->cmd;
        if (!cmd) return;
@@ -344,21 +338,23 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
 /*
  * Enable the controller
  */
-static void at91_mci_enable(void)
+static void at91_mci_enable(struct at91mci_host *host)
 {
-       at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
-       at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF);
-       at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-       at91_mci_write(AT91_MCI_MR, 0x834A);
-       at91_mci_write(AT91_MCI_SDCR, 0x0);
+       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+       at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+       at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
+
+       /* use Slot A or B (only one at same time) */
+       at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
 }
 
 /*
  * Disable the controller
  */
-static void at91_mci_disable(void)
+static void at91_mci_disable(struct at91mci_host *host)
 {
-       at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
 }
 
 /*
@@ -378,13 +374,13 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
 
        /* Not sure if this is needed */
 #if 0
-       if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+       if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
                pr_debug("Clearing timeout\n");
-               at91_mci_write(AT91_MCI_ARGR, 0);
-               at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-               while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+               at91_mci_write(host, AT91_MCI_ARGR, 0);
+               at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+               while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
                        /* spin */
-                       pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
+                       pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
                }
        }
 #endif
@@ -431,32 +427,32 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
        /*
         * Set the arguments and send the command
         */
-       pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
-               cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
+       pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
+               cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
 
        if (!data) {
-               at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
-               at91_mci_write(AT91_PDC_RPR, 0);
-               at91_mci_write(AT91_PDC_RCR, 0);
-               at91_mci_write(AT91_PDC_RNPR, 0);
-               at91_mci_write(AT91_PDC_RNCR, 0);
-               at91_mci_write(AT91_PDC_TPR, 0);
-               at91_mci_write(AT91_PDC_TCR, 0);
-               at91_mci_write(AT91_PDC_TNPR, 0);
-               at91_mci_write(AT91_PDC_TNCR, 0);
-
-               at91_mci_write(AT91_MCI_ARGR, cmd->arg);
-               at91_mci_write(AT91_MCI_CMDR, cmdr);
+               at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
+               at91_mci_write(host, AT91_PDC_RPR, 0);
+               at91_mci_write(host, AT91_PDC_RCR, 0);
+               at91_mci_write(host, AT91_PDC_RNPR, 0);
+               at91_mci_write(host, AT91_PDC_RNCR, 0);
+               at91_mci_write(host, AT91_PDC_TPR, 0);
+               at91_mci_write(host, AT91_PDC_TCR, 0);
+               at91_mci_write(host, AT91_PDC_TNPR, 0);
+               at91_mci_write(host, AT91_PDC_TNCR, 0);
+
+               at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+               at91_mci_write(host, AT91_MCI_CMDR, cmdr);
                return AT91_MCI_CMDRDY;
        }
 
-       mr = at91_mci_read(AT91_MCI_MR) & 0x7fff;       /* zero block length and PDC mode */
-       at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+       mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
+       at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
 
        /*
         * Disable the PDC controller
         */
-       at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+       at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
 
        if (cmdr & AT91_MCI_TRCMD_START) {
                data->bytes_xfered = 0;
@@ -485,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
 
                        pr_debug("Transmitting %d bytes\n", host->total_length);
 
-                       at91_mci_write(AT91_PDC_TPR, host->physical_address);
-                       at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
+                       at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
+                       at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
                        ier = AT91_MCI_TXBUFE;
                }
        }
@@ -496,14 +492,14 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
         * the data sheet says
         */
 
-       at91_mci_write(AT91_MCI_ARGR, cmd->arg);
-       at91_mci_write(AT91_MCI_CMDR, cmdr);
+       at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+       at91_mci_write(host, AT91_MCI_CMDR, cmdr);
 
        if (cmdr & AT91_MCI_TRCMD_START) {
                if (cmdr & AT91_MCI_TRDIR)
-                       at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN);
+                       at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN);
                else
-                       at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN);
+                       at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
        }
        return ier;
 }
@@ -520,7 +516,7 @@ static void at91mci_process_command(struct at91mci_host *host, struct mmc_comman
        pr_debug("setting ier to %08X\n", ier);
 
        /* Stop on errors or the required value */
-       at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
+       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
 }
 
 /*
@@ -548,19 +544,19 @@ static void at91mci_completed_command(struct at91mci_host *host)
        struct mmc_command *cmd = host->cmd;
        unsigned int status;
 
-       at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
 
-       cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0));
-       cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1));
-       cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2));
-       cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3));
+       cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
+       cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
+       cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
+       cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
 
        if (host->buffer) {
                dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
                host->buffer = NULL;
        }
 
-       status = at91_mci_read(AT91_MCI_SR);
+       status = at91_mci_read(host, AT91_MCI_SR);
 
        pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
                 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
@@ -611,18 +607,18 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        int clkdiv;
        struct at91mci_host *host = mmc_priv(mmc);
-       unsigned long at91_master_clock = clk_get_rate(mci_clk);
+       unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
 
        host->bus_mode = ios->bus_mode;
 
        if (ios->clock == 0) {
                /* Disable the MCI controller */
-               at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS);
+               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
                clkdiv = 0;
        }
        else {
                /* Enable the MCI controller */
-               at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
 
                if ((at91_master_clock % (ios->clock * 2)) == 0)
                        clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
@@ -634,25 +630,25 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
        if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
                pr_debug("MMC: Setting controller bus width to 4\n");
-               at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
        }
        else {
                pr_debug("MMC: Setting controller bus width to 1\n");
-               at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
        }
 
        /* Set the clock divider */
-       at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+       at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
 
        /* maybe switch power to the card */
        if (host->board->vcc_pin) {
                switch (ios->power_mode) {
                        case MMC_POWER_OFF:
-                               at91_set_gpio_output(host->board->vcc_pin, 0);
+                               at91_set_gpio_value(host->board->vcc_pin, 0);
                                break;
                        case MMC_POWER_UP:
                        case MMC_POWER_ON:
-                               at91_set_gpio_output(host->board->vcc_pin, 1);
+                               at91_set_gpio_value(host->board->vcc_pin, 1);
                                break;
                }
        }
@@ -665,39 +661,40 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
 {
        struct at91mci_host *host = devid;
        int completed = 0;
+       unsigned int int_status, int_mask;
 
-       unsigned int int_status;
+       int_status = at91_mci_read(host, AT91_MCI_SR);
+       int_mask = at91_mci_read(host, AT91_MCI_IMR);
+       
+       pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
+               int_status & int_mask);
+       
+       int_status = int_status & int_mask;
 
-       int_status = at91_mci_read(AT91_MCI_SR);
-       pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
-               int_status & at91_mci_read(AT91_MCI_IMR));
-
-       if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
+       if (int_status & AT91_MCI_ERRORS) {
                completed = 1;
+               
+               if (int_status & AT91_MCI_UNRE)
+                       pr_debug("MMC: Underrun error\n");
+               if (int_status & AT91_MCI_OVRE)
+                       pr_debug("MMC: Overrun error\n");
+               if (int_status & AT91_MCI_DTOE)
+                       pr_debug("MMC: Data timeout\n");
+               if (int_status & AT91_MCI_DCRCE)
+                       pr_debug("MMC: CRC error in data\n");
+               if (int_status & AT91_MCI_RTOE)
+                       pr_debug("MMC: Response timeout\n");
+               if (int_status & AT91_MCI_RENDE)
+                       pr_debug("MMC: Response end bit error\n");
+               if (int_status & AT91_MCI_RCRCE)
+                       pr_debug("MMC: Response CRC error\n");
+               if (int_status & AT91_MCI_RDIRE)
+                       pr_debug("MMC: Response direction error\n");
+               if (int_status & AT91_MCI_RINDE)
+                       pr_debug("MMC: Response index error\n");
+       } else {
+               /* Only continue processing if no errors */
 
-       int_status &= at91_mci_read(AT91_MCI_IMR);
-
-       if (int_status & AT91_MCI_UNRE)
-               pr_debug("MMC: Underrun error\n");
-       if (int_status & AT91_MCI_OVRE)
-               pr_debug("MMC: Overrun error\n");
-       if (int_status & AT91_MCI_DTOE)
-               pr_debug("MMC: Data timeout\n");
-       if (int_status & AT91_MCI_DCRCE)
-               pr_debug("MMC: CRC error in data\n");
-       if (int_status & AT91_MCI_RTOE)
-               pr_debug("MMC: Response timeout\n");
-       if (int_status & AT91_MCI_RENDE)
-               pr_debug("MMC: Response end bit error\n");
-       if (int_status & AT91_MCI_RCRCE)
-               pr_debug("MMC: Response CRC error\n");
-       if (int_status & AT91_MCI_RDIRE)
-               pr_debug("MMC: Response direction error\n");
-       if (int_status & AT91_MCI_RINDE)
-               pr_debug("MMC: Response index error\n");
-
-       /* Only continue processing if no errors */
-       if (!completed) {
                if (int_status & AT91_MCI_TXBUFE) {
                        pr_debug("TX buffer empty\n");
                        at91_mci_handle_transmitted(host);
@@ -705,12 +702,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
 
                if (int_status & AT91_MCI_RXBUFF) {
                        pr_debug("RX buffer full\n");
-                       at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
                }
 
-               if (int_status & AT91_MCI_ENDTX) {
+               if (int_status & AT91_MCI_ENDTX)
                        pr_debug("Transmit has ended\n");
-               }
 
                if (int_status & AT91_MCI_ENDRX) {
                        pr_debug("Receive has ended\n");
@@ -719,37 +715,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid)
 
                if (int_status & AT91_MCI_NOTBUSY) {
                        pr_debug("Card is ready\n");
-                       at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
                }
 
-               if (int_status & AT91_MCI_DTIP) {
+               if (int_status & AT91_MCI_DTIP)
                        pr_debug("Data transfer in progress\n");
-               }
 
-               if (int_status & AT91_MCI_BLKE) {
+               if (int_status & AT91_MCI_BLKE)
                        pr_debug("Block transfer has ended\n");
-               }
 
-               if (int_status & AT91_MCI_TXRDY) {
+               if (int_status & AT91_MCI_TXRDY)
                        pr_debug("Ready to transmit\n");
-               }
 
-               if (int_status & AT91_MCI_RXRDY) {
+               if (int_status & AT91_MCI_RXRDY)
                        pr_debug("Ready to receive\n");
-               }
 
                if (int_status & AT91_MCI_CMDRDY) {
                        pr_debug("Command ready\n");
                        completed = 1;
                }
        }
-       at91_mci_write(AT91_MCI_IDR, int_status);
 
        if (completed) {
                pr_debug("Completed command\n");
-               at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+               at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
                at91mci_completed_command(host);
-       }
+       } else
+               at91_mci_write(host, AT91_MCI_IDR, int_status);
 
        return IRQ_HANDLED;
 }
@@ -769,7 +761,7 @@ static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
                        present ? "insert" : "remove");
                if (!present) {
                        pr_debug("****** Resetting SD-card bus width ******\n");
-                       at91_mci_write(AT91_MCI_SDCR, 0);
+                       at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
                }
                mmc_detect_change(host->mmc, msecs_to_jiffies(100));
        }
@@ -806,15 +798,22 @@ static int at91_mci_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
        struct at91mci_host *host;
+       struct resource *res;
        int ret;
 
        pr_debug("Probe MCI devices\n");
-       at91_mci_disable();
-       at91_mci_enable();
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+               return -EBUSY;
 
        mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
        if (!mmc) {
                pr_debug("Failed to allocate mmc host\n");
+               release_mem_region(res->start, res->end - res->start + 1);
                return -ENOMEM;
        }
 
@@ -833,30 +832,51 @@ static int at91_mci_probe(struct platform_device *pdev)
 #ifdef SUPPORT_4WIRE
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 #else
-               printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+               printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
 #endif
        }
 
        /*
         * Get Clock
         */
-       mci_clk = clk_get(&pdev->dev, "mci_clk");
-       if (IS_ERR(mci_clk)) {
+       host->mci_clk = clk_get(&pdev->dev, "mci_clk");
+       if (IS_ERR(host->mci_clk)) {
                printk(KERN_ERR "AT91 MMC: no clock defined.\n");
                mmc_free_host(mmc);
+               release_mem_region(res->start, res->end - res->start + 1);
                return -ENODEV;
        }
-       clk_enable(mci_clk);                    /* Enable the peripheral clock */
+
+       /*
+        * Map I/O region
+        */
+       host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+       if (!host->baseaddr) {
+               clk_put(host->mci_clk);
+               mmc_free_host(mmc);
+               release_mem_region(res->start, res->end - res->start + 1);
+               return -ENOMEM;
+       }
+
+       /*
+        * Reset hardware
+        */
+       clk_enable(host->mci_clk);              /* Enable the peripheral clock */
+       at91_mci_disable(host);
+       at91_mci_enable(host);
 
        /*
         * Allocate the MCI interrupt
         */
-       ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+       host->irq = platform_get_irq(pdev, 0);
+       ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
        if (ret) {
-               printk(KERN_ERR "Failed to request MCI interrupt\n");
-               clk_disable(mci_clk);
-               clk_put(mci_clk);
+               printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
+               clk_disable(host->mci_clk);
+               clk_put(host->mci_clk);
                mmc_free_host(mmc);
+               iounmap(host->baseaddr);
+               release_mem_region(res->start, res->end - res->start + 1);
                return ret;
        }
 
@@ -879,10 +899,10 @@ static int at91_mci_probe(struct platform_device *pdev)
                ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
                                0, DRIVER_NAME, host);
                if (ret)
-                       printk(KERN_ERR "couldn't allocate MMC detect irq\n");
+                       printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
        }
 
-       pr_debug(KERN_INFO "Added MCI driver\n");
+       pr_debug("Added MCI driver\n");
 
        return 0;
 }
@@ -894,6 +914,7 @@ static int at91_mci_remove(struct platform_device *pdev)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct at91mci_host *host;
+       struct resource *res;
 
        if (!mmc)
                return -1;
@@ -905,16 +926,19 @@ static int at91_mci_remove(struct platform_device *pdev)
                cancel_delayed_work(&host->mmc->detect);
        }
 
+       at91_mci_disable(host);
        mmc_remove_host(mmc);
-       at91_mci_disable();
-       free_irq(AT91RM9200_ID_MCI, host);
-       mmc_free_host(mmc);
+       free_irq(host->irq, host);
 
-       clk_disable(mci_clk);                           /* Disable the peripheral clock */
-       clk_put(mci_clk);
+       clk_disable(host->mci_clk);                     /* Disable the peripheral clock */
+       clk_put(host->mci_clk);
 
-       platform_set_drvdata(pdev, NULL);
+       iounmap(host->baseaddr);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, res->end - res->start + 1);
 
+       mmc_free_host(mmc);
+       platform_set_drvdata(pdev, NULL);
        pr_debug("MCI Removed\n");
 
        return 0;
index a17423a4ed8fb9cbcc4b41e3ea0fcd7a4a7cb744..3e35a43819fba1a75c00d7cdac55265cda17f9f8 100644 (file)
@@ -78,8 +78,10 @@ static int mmc_queue_thread(void *d)
                spin_unlock_irq(q->queue_lock);
 
                if (!req) {
-                       if (kthread_should_stop())
+                       if (kthread_should_stop()) {
+                               set_current_state(TASK_RUNNING);
                                break;
+                       }
                        up(&mq->thread_sem);
                        schedule();
                        down(&mq->thread_sem);
index cd98117632d38e66687ad8aa91185c5dccf9a067..c2d13d7e99111f986e4c4d136f3c72ba95a5f4d8 100644 (file)
@@ -1170,8 +1170,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        }
 
        if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
-               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. Aborting.\n");
-               return -ENODEV;
+               printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
+                       "You may experience problems.\n");
        }
 
        if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
index 931028f672de0eb610622895927db75b3bc23d57..35ad5cff18e65936862c20276de4468189a12568 100644 (file)
@@ -2131,14 +2131,15 @@ static int rtl8139_poll(struct net_device *dev, int *budget)
        }
 
        if (done) {
+               unsigned long flags;
                /*
                 * Order is important since data can get interrupted
                 * again when we think we are done.
                 */
-               local_irq_disable();
+               local_irq_save(flags);
                RTL_W16_F(IntrMask, rtl8139_intr_mask);
                __netif_rx_complete(dev);
-               local_irq_enable();
+               local_irq_restore(flags);
        }
        spin_unlock(&tp->rx_lock);
 
index 9de0eed6755b38028b67e343a8d1b8dca29288fe..8aa8dd02b910cb4a2000f959ea175907c3525e04 100644 (file)
@@ -2384,6 +2384,14 @@ config CHELSIO_T1_1G
           Enables support for Chelsio's gigabit Ethernet PCI cards.  If you
           are using only 10G cards say 'N' here.
 
+config CHELSIO_T1_NAPI
+       bool "Use Rx Polling (NAPI)"
+       depends on CHELSIO_T1
+       default y
+       help
+         NAPI is a driver API designed to reduce CPU and interrupt load
+         when the driver is receiving lots of packets from the card.
+
 config EHEA
        tristate "eHEA Ethernet support"
        depends on IBMEBUS
index de48eadddbc4af9fa09452fea78b22ec7f17cf9c..fd5d821f3f2a3c550834b55988f4457fdd0e1392 100644 (file)
@@ -220,9 +220,8 @@ static int cxgb_up(struct adapter *adapter)
 
        t1_interrupts_clear(adapter);
 
-       adapter->params.has_msi = !disable_msi && pci_enable_msi(adapter->pdev) == 0;
-       err = request_irq(adapter->pdev->irq,
-                         t1_select_intr_handler(adapter),
+       adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev);
+       err = request_irq(adapter->pdev->irq, t1_interrupt,
                          adapter->params.has_msi ? 0 : IRQF_SHARED,
                          adapter->name, adapter);
        if (err) {
@@ -764,18 +763,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
        struct adapter *adapter = dev->priv;
 
-       /*
-        * If RX coalescing is requested we use NAPI, otherwise interrupts.
-        * This choice can be made only when all ports and the TOE are off.
-        */
-       if (adapter->open_device_map == 0)
-               adapter->params.sge.polling = c->use_adaptive_rx_coalesce;
-
-       if (adapter->params.sge.polling) {
-               adapter->params.sge.rx_coalesce_usecs = 0;
-       } else {
-               adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
-       }
+       adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
        adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
        adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
        t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
@@ -944,7 +932,7 @@ static void t1_netpoll(struct net_device *dev)
        struct adapter *adapter = dev->priv;
 
        local_irq_save(flags);
-       t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter);
+       t1_interrupt(adapter->pdev->irq, adapter);
        local_irq_restore(flags);
 }
 #endif
@@ -1165,7 +1153,10 @@ static int __devinit init_one(struct pci_dev *pdev,
 #ifdef CONFIG_NET_POLL_CONTROLLER
                netdev->poll_controller = t1_netpoll;
 #endif
+#ifdef CONFIG_CHELSIO_T1_NAPI
                netdev->weight = 64;
+               netdev->poll = t1_poll;
+#endif
 
                SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
        }
index 0ca8d876e16f41903fba9a0530e536f836447f83..659cb2252e4439a77a00f90e8cb711c41c2be40c 100644 (file)
@@ -1413,16 +1413,20 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
 
        if (unlikely(adapter->vlan_grp && p->vlan_valid)) {
                st->vlan_xtract++;
-               if (adapter->params.sge.polling)
+#ifdef CONFIG_CHELSIO_T1_NAPI
                        vlan_hwaccel_receive_skb(skb, adapter->vlan_grp,
                                                 ntohs(p->vlan));
-               else
+#else
                        vlan_hwaccel_rx(skb, adapter->vlan_grp,
                                        ntohs(p->vlan));
-       } else if (adapter->params.sge.polling)
+#endif
+       } else {
+#ifdef CONFIG_CHELSIO_T1_NAPI
                netif_receive_skb(skb);
-       else
+#else
                netif_rx(skb);
+#endif
+       }
        return 0;
 }
 
@@ -1572,6 +1576,7 @@ static int process_responses(struct adapter *adapter, int budget)
        return budget;
 }
 
+#ifdef CONFIG_CHELSIO_T1_NAPI
 /*
  * A simpler version of process_responses() that handles only pure (i.e.,
  * non data-carrying) responses.  Such respones are too light-weight to justify
@@ -1619,92 +1624,76 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
  * or protection from interrupts as data interrupts are off at this point and
  * other adapter interrupts do not interfere.
  */
-static int t1_poll(struct net_device *dev, int *budget)
+int t1_poll(struct net_device *dev, int *budget)
 {
        struct adapter *adapter = dev->priv;
        int effective_budget = min(*budget, dev->quota);
-
        int work_done = process_responses(adapter, effective_budget);
+
        *budget -= work_done;
        dev->quota -= work_done;
 
        if (work_done >= effective_budget)
                return 1;
 
+       spin_lock_irq(&adapter->async_lock);
        __netif_rx_complete(dev);
-
-       /*
-        * Because we don't atomically flush the following write it is
-        * possible that in very rare cases it can reach the device in a way
-        * that races with a new response being written plus an error interrupt
-        * causing the NAPI interrupt handler below to return unhandled status
-        * to the OS.  To protect against this would require flushing the write
-        * and doing both the write and the flush with interrupts off.  Way too
-        * expensive and unjustifiable given the rarity of the race.
-        */
        writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-       return 0;
-}
+       writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
+              adapter->regs + A_PL_ENABLE);
+       spin_unlock_irq(&adapter->async_lock);
 
-/*
- * Returns true if the device is already scheduled for polling.
- */
-static inline int napi_is_scheduled(struct net_device *dev)
-{
-       return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+       return 0;
 }
 
 /*
  * NAPI version of the main interrupt handler.
  */
-static irqreturn_t t1_interrupt_napi(int irq, void *data)
+irqreturn_t t1_interrupt(int irq, void *data)
 {
-       int handled;
        struct adapter *adapter = data;
+       struct net_device *dev = adapter->sge->netdev;
        struct sge *sge = adapter->sge;
-       struct respQ *q = &adapter->sge->respQ;
+       u32 cause;
+       int handled = 0;
 
-       /*
-        * Clear the SGE_DATA interrupt first thing.  Normally the NAPI
-        * handler has control of the response queue and the interrupt handler
-        * can look at the queue reliably only once it knows NAPI is off.
-        * We can't wait that long to clear the SGE_DATA interrupt because we
-        * could race with t1_poll rearming the SGE interrupt, so we need to
-        * clear the interrupt speculatively and really early on.
-        */
-       writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+       cause = readl(adapter->regs + A_PL_CAUSE);
+       if (cause == 0 || cause == ~0)
+               return IRQ_NONE;
 
        spin_lock(&adapter->async_lock);
-       if (!napi_is_scheduled(sge->netdev)) {
+       if (cause & F_PL_INTR_SGE_DATA) {
+               struct respQ *q = &adapter->sge->respQ;
                struct respQ_e *e = &q->entries[q->cidx];
 
-               if (e->GenerationBit == q->genbit) {
-                       if (e->DataValid ||
-                           process_pure_responses(adapter, e)) {
-                               if (likely(__netif_rx_schedule_prep(sge->netdev)))
-                                       __netif_rx_schedule(sge->netdev);
-                               else if (net_ratelimit())
-                                       printk(KERN_INFO
-                                              "NAPI schedule failure!\n");
-                       } else
-                               writel(q->cidx, adapter->regs + A_SG_SLEEPING);
-
-                       handled = 1;
-                       goto unlock;
-               } else
-                       writel(q->cidx, adapter->regs + A_SG_SLEEPING);
-       }  else if (readl(adapter->regs + A_PL_CAUSE) & F_PL_INTR_SGE_DATA) {
-               printk(KERN_ERR "data interrupt while NAPI running\n");
-       }
-       
-       handled = t1_slow_intr_handler(adapter);
+               handled = 1;
+               writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+
+               if (e->GenerationBit == q->genbit &&
+                   __netif_rx_schedule_prep(dev)) {
+                       if (e->DataValid || process_pure_responses(adapter, e)) {
+                               /* mask off data IRQ */
+                               writel(adapter->slow_intr_mask,
+                                      adapter->regs + A_PL_ENABLE);
+                               __netif_rx_schedule(sge->netdev);
+                               goto unlock;
+                       }
+                       /* no data, no NAPI needed */
+                       netif_poll_enable(dev);
+
+               }
+               writel(q->cidx, adapter->regs + A_SG_SLEEPING);
+       } else
+               handled = t1_slow_intr_handler(adapter);
+
        if (!handled)
                sge->stats.unhandled_irqs++;
- unlock:
+unlock:
        spin_unlock(&adapter->async_lock);
        return IRQ_RETVAL(handled != 0);
 }
 
+#else
 /*
  * Main interrupt handler, optimized assuming that we took a 'DATA'
  * interrupt.
@@ -1720,7 +1709,7 @@ static irqreturn_t t1_interrupt_napi(int irq, void *data)
  * 5. If we took an interrupt, but no valid respQ descriptors was found we
  *      let the slow_intr_handler run and do error handling.
  */
-static irqreturn_t t1_interrupt(int irq, void *cookie)
+irqreturn_t t1_interrupt(int irq, void *cookie)
 {
        int work_done;
        struct respQ_e *e;
@@ -1752,11 +1741,7 @@ static irqreturn_t t1_interrupt(int irq, void *cookie)
        spin_unlock(&adapter->async_lock);
        return IRQ_RETVAL(work_done != 0);
 }
-
-irq_handler_t t1_select_intr_handler(adapter_t *adapter)
-{
-       return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt;
-}
+#endif
 
 /*
  * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it.
@@ -2033,7 +2018,6 @@ static void sge_tx_reclaim_cb(unsigned long data)
  */
 int t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p)
 {
-       sge->netdev->poll = t1_poll;
        sge->fixed_intrtimer = p->rx_coalesce_usecs *
                core_ticks_per_usec(sge->adapter);
        writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER);
@@ -2234,7 +2218,6 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
 
        p->coalesce_enable = 0;
        p->sample_interval_usecs = 0;
-       p->polling = 0;
 
        return sge;
 nomem_port:
index 7ceb0117d0396250d0f83e89ba461501621973fe..d132a0ef2a2204361ec3f7a16635d9058bf25c29 100644 (file)
@@ -76,7 +76,9 @@ struct sge *t1_sge_create(struct adapter *, struct sge_params *);
 int t1_sge_configure(struct sge *, struct sge_params *);
 int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
 void t1_sge_destroy(struct sge *);
-irq_handler_t t1_select_intr_handler(adapter_t *adapter);
+irqreturn_t t1_interrupt(int irq, void *cookie);
+int t1_poll(struct net_device *, int *);
+
 int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
 void t1_set_vlan_accel(struct adapter *adapter, int on_off);
 void t1_sge_start(struct sge *);
index 8a83db0fb3b75c6be9232aed06153e08897c543c..153b6dc80af4c38bebcca28a4cf8afc6a4209124 100644 (file)
@@ -1177,7 +1177,7 @@ static void baycom_probe(struct net_device *dev)
        dev->mtu = AX25_DEF_PACLEN;        /* eth_mtu is the default */
        dev->addr_len = AX25_ADDR_LEN;     /* sizeof an ax.25 address */
        memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
-       memcpy(dev->dev_addr, &ax25_nocall, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr, &null_ax25_address, AX25_ADDR_LEN);
        dev->tx_queue_len = 16;
 
        /* New style flags */
index bd0ce98c939cac1c5da1539df365866cb552c773..25b559b5d5ede142390236a0145a327b9bc9df1c 100644 (file)
@@ -264,12 +264,12 @@ static void macb_update_stats(struct macb *bp)
        WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
 
        for(; p < end; p++, reg++)
-               *p += readl(reg);
+               *p += __raw_readl(reg);
 }
 
-static void macb_periodic_task(void *arg)
+static void macb_periodic_task(struct work_struct *work)
 {
-       struct macb *bp = arg;
+       struct macb *bp = container_of(work, struct macb, periodic_task.work);
 
        macb_update_stats(bp);
        macb_check_media(bp, 1, 0);
@@ -1088,7 +1088,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
 
        dev->base_addr = regs->start;
 
-       INIT_WORK(&bp->periodic_task, macb_periodic_task, bp);
+       INIT_DELAYED_WORK(&bp->periodic_task, macb_periodic_task);
        mutex_init(&bp->mdio_mutex);
        init_completion(&bp->mdio_complete);
 
index 8c253db69881d9afc1c420c5152487fbf384c82a..27bf0ae0f0bb8310136e749fa94d8d495d92d09d 100644 (file)
 
 /* Register access macros */
 #define macb_readl(port,reg)                           \
-       readl((port)->regs + MACB_##reg)
+       __raw_readl((port)->regs + MACB_##reg)
 #define macb_writel(port,reg,value)                    \
-       writel((value), (port)->regs + MACB_##reg)
+       __raw_writel((value), (port)->regs + MACB_##reg)
 
 struct dma_desc {
        u32     addr;
@@ -377,7 +377,7 @@ struct macb {
 
        unsigned int            rx_pending, tx_pending;
 
-       struct work_struct      periodic_task;
+       struct delayed_work     periodic_task;
 
        struct mutex            mdio_mutex;
        struct completion       mdio_complete;
index 81f127a78afae71206afde2a32ec4295c068aa20..94ac168be59376abba77f85f15dce0d10e32264a 100644 (file)
@@ -71,7 +71,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.0.0"
+#define MYRI10GE_VERSION_STR "1.1.0"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -92,8 +92,13 @@ MODULE_LICENSE("Dual BSD/GPL");
 #define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
 #define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
 
+#define MYRI10GE_ALLOC_ORDER 0
+#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)
+#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)
+
 struct myri10ge_rx_buffer_state {
-       struct sk_buff *skb;
+       struct page *page;
+       int page_offset;
         DECLARE_PCI_UNMAP_ADDR(bus)
         DECLARE_PCI_UNMAP_LEN(len)
 };
@@ -116,9 +121,14 @@ struct myri10ge_rx_buf {
        u8 __iomem *wc_fifo;    /* w/c rx dma addr fifo address */
        struct mcp_kreq_ether_recv *shadow;     /* host shadow of recv ring */
        struct myri10ge_rx_buffer_state *info;
+       struct page *page;
+       dma_addr_t bus;
+       int page_offset;
        int cnt;
+       int fill_cnt;
        int alloc_fail;
        int mask;               /* number of rx slots -1 */
+       int watchdog_needed;
 };
 
 struct myri10ge_tx_buf {
@@ -150,6 +160,7 @@ struct myri10ge_priv {
        struct myri10ge_rx_buf rx_big;
        struct myri10ge_rx_done rx_done;
        int small_bytes;
+       int big_bytes;
        struct net_device *dev;
        struct net_device_stats stats;
        u8 __iomem *sram;
@@ -238,11 +249,6 @@ module_param(myri10ge_force_firmware, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_force_firmware,
                 "Force firmware to assume aligned completions\n");
 
-static int myri10ge_skb_cross_4k = 0;
-module_param(myri10ge_skb_cross_4k, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(myri10ge_skb_cross_4k,
-                "Can a small skb cross a 4KB boundary?\n");
-
 static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
 module_param(myri10ge_initial_mtu, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");
@@ -266,6 +272,10 @@ static int myri10ge_debug = -1;    /* defaults above */
 module_param(myri10ge_debug, int, 0);
 MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
 
+static int myri10ge_fill_thresh = 256;
+module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
+
 #define MYRI10GE_FW_OFFSET 1024*1024
 #define MYRI10GE_HIGHPART_TO_U32(X) \
 (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -273,9 +283,9 @@ MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
 
 #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
 
-static inline void put_be32(__be32 val, __be32 __iomem *p)
+static inline void put_be32(__be32 val, __be32 __iomem * p)
 {
-       __raw_writel((__force __u32)val, (__force void __iomem *)p);
+       __raw_writel((__force __u32) val, (__force void __iomem *)p);
 }
 
 static int
@@ -804,194 +814,179 @@ myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
        mb();
 }
 
-/*
- * Set of routines to get a new receive buffer.  Any buffer which
- * crosses a 4KB boundary must start on a 4KB boundary due to PCIe
- * wdma restrictions. We also try to align any smaller allocation to
- * at least a 16 byte boundary for efficiency.  We assume the linux
- * memory allocator works by powers of 2, and will not return memory
- * smaller than 2KB which crosses a 4KB boundary.  If it does, we fall
- * back to allocating 2x as much space as required.
- *
- * We intend to replace large (>4KB) skb allocations by using
- * pages directly and building a fraglist in the near future.
- */
-
-static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
-                                                int bytes)
-{
-       struct sk_buff *skb;
-       unsigned long data, roundup;
-
-       skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
-       if (skb == NULL)
-               return NULL;
-
-       /* Correct skb->truesize so that socket buffer
-        * accounting is not confused the rounding we must
-        * do to satisfy alignment constraints.
-        */
-       skb->truesize -= 4096;
-
-       data = (unsigned long)(skb->data);
-       roundup = (-data) & (4095);
-       skb_reserve(skb, roundup);
-       return skb;
-}
-
-/* Allocate 2x as much space as required and use whichever portion
- * does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
-                                                       unsigned int bytes)
+static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum)
 {
-       struct sk_buff *skb;
-       unsigned long data, boundary;
-
-       skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
-       if (unlikely(skb == NULL))
-               return NULL;
-
-       /* Correct skb->truesize so that socket buffer
-        * accounting is not confused the rounding we must
-        * do to satisfy alignment constraints.
-        */
-       skb->truesize -= bytes + MXGEFW_PAD;
-
-       data = (unsigned long)(skb->data);
-       boundary = (data + 4095UL) & ~4095UL;
-       if ((boundary - data) >= (bytes + MXGEFW_PAD))
-               return skb;
+       struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
 
-       skb_reserve(skb, boundary - data);
-       return skb;
+       if ((skb->protocol == htons(ETH_P_8021Q)) &&
+           (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
+            vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
+               skb->csum = hw_csum;
+               skb->ip_summed = CHECKSUM_COMPLETE;
+       }
 }
 
-/* Allocate just enough space, and verify that the allocated
- * space does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
-                                                  int bytes)
+static inline void
+myri10ge_rx_skb_build(struct sk_buff *skb, u8 * va,
+                     struct skb_frag_struct *rx_frags, int len, int hlen)
 {
-       struct sk_buff *skb;
-       unsigned long roundup, data, end;
-
-       skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
-       if (unlikely(skb == NULL))
-               return NULL;
-
-       /* Round allocated buffer to 16 byte boundary */
-       data = (unsigned long)(skb->data);
-       roundup = (-data) & 15UL;
-       skb_reserve(skb, roundup);
-       /* Verify that the data buffer does not cross a page boundary */
-       data = (unsigned long)(skb->data);
-       end = data + bytes + MXGEFW_PAD - 1;
-       if (unlikely(((end >> 12) != (data >> 12)) && (data & 4095UL))) {
-               printk(KERN_NOTICE
-                      "myri10ge_alloc_small: small skb crossed 4KB boundary\n");
-               myri10ge_skb_cross_4k = 1;
-               dev_kfree_skb_any(skb);
-               skb = myri10ge_alloc_small_safe(dev, bytes);
-       }
-       return skb;
+       struct skb_frag_struct *skb_frags;
+
+       skb->len = skb->data_len = len;
+       skb->truesize = len + sizeof(struct sk_buff);
+       /* attach the page(s) */
+
+       skb_frags = skb_shinfo(skb)->frags;
+       while (len > 0) {
+               memcpy(skb_frags, rx_frags, sizeof(*skb_frags));
+               len -= rx_frags->size;
+               skb_frags++;
+               rx_frags++;
+               skb_shinfo(skb)->nr_frags++;
+       }
+
+       /* pskb_may_pull is not available in irq context, but
+        * skb_pull() (for ether_pad and eth_type_trans()) requires
+        * the beginning of the packet in skb_headlen(), move it
+        * manually */
+       memcpy(skb->data, va, hlen);
+       skb_shinfo(skb)->frags[0].page_offset += hlen;
+       skb_shinfo(skb)->frags[0].size -= hlen;
+       skb->data_len -= hlen;
+       skb->tail += hlen;
+       skb_pull(skb, MXGEFW_PAD);
 }
 
-static inline int
-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
-               int bytes, int idx)
+static void
+myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
+                       int bytes, int watchdog)
 {
-       struct net_device *dev = mgp->dev;
-       struct pci_dev *pdev = mgp->pdev;
-       struct sk_buff *skb;
-       dma_addr_t bus;
-       int len, retval = 0;
+       struct page *page;
+       int idx;
 
-       bytes += VLAN_HLEN;     /* account for 802.1q vlan tag */
+       if (unlikely(rx->watchdog_needed && !watchdog))
+               return;
 
-       if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
-               skb = myri10ge_alloc_big(dev, bytes);
-       else if (myri10ge_skb_cross_4k)
-               skb = myri10ge_alloc_small_safe(dev, bytes);
-       else
-               skb = myri10ge_alloc_small(dev, bytes);
+       /* try to refill entire ring */
+       while (rx->fill_cnt != (rx->cnt + rx->mask + 1)) {
+               idx = rx->fill_cnt & rx->mask;
 
-       if (unlikely(skb == NULL)) {
-               rx->alloc_fail++;
-               retval = -ENOBUFS;
-               goto done;
-       }
-
-       /* set len so that it only covers the area we
-        * need mapped for DMA */
-       len = bytes + MXGEFW_PAD;
-
-       bus = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
-       rx->info[idx].skb = skb;
-       pci_unmap_addr_set(&rx->info[idx], bus, bus);
-       pci_unmap_len_set(&rx->info[idx], len, len);
-       rx->shadow[idx].addr_low = htonl(MYRI10GE_LOWPART_TO_U32(bus));
-       rx->shadow[idx].addr_high = htonl(MYRI10GE_HIGHPART_TO_U32(bus));
-
-done:
-       /* copy 8 descriptors (64-bytes) to the mcp at a time */
-       if ((idx & 7) == 7) {
-               if (rx->wc_fifo == NULL)
-                       myri10ge_submit_8rx(&rx->lanai[idx - 7],
-                                           &rx->shadow[idx - 7]);
-               else {
-                       mb();
-                       myri10ge_pio_copy(rx->wc_fifo,
-                                         &rx->shadow[idx - 7], 64);
+               if ((bytes < MYRI10GE_ALLOC_SIZE / 2) &&
+                   (rx->page_offset + bytes <= MYRI10GE_ALLOC_SIZE)) {
+                       /* we can use part of previous page */
+                       get_page(rx->page);
+               } else {
+                       /* we need a new page */
+                       page =
+                           alloc_pages(GFP_ATOMIC | __GFP_COMP,
+                                       MYRI10GE_ALLOC_ORDER);
+                       if (unlikely(page == NULL)) {
+                               if (rx->fill_cnt - rx->cnt < 16)
+                                       rx->watchdog_needed = 1;
+                               return;
+                       }
+                       rx->page = page;
+                       rx->page_offset = 0;
+                       rx->bus = pci_map_page(mgp->pdev, page, 0,
+                                              MYRI10GE_ALLOC_SIZE,
+                                              PCI_DMA_FROMDEVICE);
+               }
+               rx->info[idx].page = rx->page;
+               rx->info[idx].page_offset = rx->page_offset;
+               /* note that this is the address of the start of the
+                * page */
+               pci_unmap_addr_set(&rx->info[idx], bus, rx->bus);
+               rx->shadow[idx].addr_low =
+                   htonl(MYRI10GE_LOWPART_TO_U32(rx->bus) + rx->page_offset);
+               rx->shadow[idx].addr_high =
+                   htonl(MYRI10GE_HIGHPART_TO_U32(rx->bus));
+
+               /* start next packet on a cacheline boundary */
+               rx->page_offset += SKB_DATA_ALIGN(bytes);
+               rx->fill_cnt++;
+
+               /* copy 8 descriptors to the firmware at a time */
+               if ((idx & 7) == 7) {
+                       if (rx->wc_fifo == NULL)
+                               myri10ge_submit_8rx(&rx->lanai[idx - 7],
+                                                   &rx->shadow[idx - 7]);
+                       else {
+                               mb();
+                               myri10ge_pio_copy(rx->wc_fifo,
+                                                 &rx->shadow[idx - 7], 64);
+                       }
                }
        }
-       return retval;
 }
 
-static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, __wsum hw_csum)
+static inline void
+myri10ge_unmap_rx_page(struct pci_dev *pdev,
+                      struct myri10ge_rx_buffer_state *info, int bytes)
 {
-       struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data);
-
-       if ((skb->protocol == htons(ETH_P_8021Q)) &&
-           (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
-            vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
-               skb->csum = hw_csum;
-               skb->ip_summed = CHECKSUM_COMPLETE;
+       /* unmap the recvd page if we're the only or last user of it */
+       if (bytes >= MYRI10GE_ALLOC_SIZE / 2 ||
+           (info->page_offset + 2 * bytes) > MYRI10GE_ALLOC_SIZE) {
+               pci_unmap_page(pdev, (pci_unmap_addr(info, bus)
+                                     & ~(MYRI10GE_ALLOC_SIZE - 1)),
+                              MYRI10GE_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
        }
 }
 
-static inline unsigned long
+#define MYRI10GE_HLEN 64       /* The number of bytes to copy from a
+                                * page into an skb */
+
+static inline int
 myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
                 int bytes, int len, __wsum csum)
 {
-       dma_addr_t bus;
        struct sk_buff *skb;
-       int idx, unmap_len;
+       struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
+       int i, idx, hlen, remainder;
+       struct pci_dev *pdev = mgp->pdev;
+       struct net_device *dev = mgp->dev;
+       u8 *va;
 
+       len += MXGEFW_PAD;
        idx = rx->cnt & rx->mask;
-       rx->cnt++;
+       va = page_address(rx->info[idx].page) + rx->info[idx].page_offset;
+       prefetch(va);
+       /* Fill skb_frag_struct(s) with data from our receive */
+       for (i = 0, remainder = len; remainder > 0; i++) {
+               myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes);
+               rx_frags[i].page = rx->info[idx].page;
+               rx_frags[i].page_offset = rx->info[idx].page_offset;
+               if (remainder < MYRI10GE_ALLOC_SIZE)
+                       rx_frags[i].size = remainder;
+               else
+                       rx_frags[i].size = MYRI10GE_ALLOC_SIZE;
+               rx->cnt++;
+               idx = rx->cnt & rx->mask;
+               remainder -= MYRI10GE_ALLOC_SIZE;
+       }
+
+       hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
 
-       /* save a pointer to the received skb */
-       skb = rx->info[idx].skb;
-       bus = pci_unmap_addr(&rx->info[idx], bus);
-       unmap_len = pci_unmap_len(&rx->info[idx], len);
+       /* allocate an skb to attach the page(s) to. */
 
-       /* try to replace the received skb */
-       if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
-               /* drop the frame -- the old skbuf is re-cycled */
-               mgp->stats.rx_dropped += 1;
+       skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
+       if (unlikely(skb == NULL)) {
+               mgp->stats.rx_dropped++;
+               do {
+                       i--;
+                       put_page(rx_frags[i].page);
+               } while (i != 0);
                return 0;
        }
 
-       /* unmap the recvd skb */
-       pci_unmap_single(mgp->pdev, bus, unmap_len, PCI_DMA_FROMDEVICE);
-
-       /* mcp implicitly skips 1st bytes so that packet is properly
-        * aligned */
-       skb_reserve(skb, MXGEFW_PAD);
-
-       /* set the length of the frame */
-       skb_put(skb, len);
+       /* Attach the pages to the skb, and trim off any padding */
+       myri10ge_rx_skb_build(skb, va, rx_frags, len, hlen);
+       if (skb_shinfo(skb)->frags[0].size <= 0) {
+               put_page(skb_shinfo(skb)->frags[0].page);
+               skb_shinfo(skb)->nr_frags = 0;
+       }
+       skb->protocol = eth_type_trans(skb, dev);
+       skb->dev = dev;
 
-       skb->protocol = eth_type_trans(skb, mgp->dev);
        if (mgp->csum_flag) {
                if ((skb->protocol == htons(ETH_P_IP)) ||
                    (skb->protocol == htons(ETH_P_IPV6))) {
@@ -1000,9 +995,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
                } else
                        myri10ge_vlan_ip_csum(skb, csum);
        }
-
        netif_receive_skb(skb);
-       mgp->dev->last_rx = jiffies;
+       dev->last_rx = jiffies;
        return 1;
 }
 
@@ -1079,7 +1073,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
                                                 length, checksum);
                else
                        rx_ok = myri10ge_rx_done(mgp, &mgp->rx_big,
-                                                mgp->dev->mtu + ETH_HLEN,
+                                                mgp->big_bytes,
                                                 length, checksum);
                rx_packets += rx_ok;
                rx_bytes += rx_ok * (unsigned long)length;
@@ -1094,6 +1088,14 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
        rx_done->cnt = cnt;
        mgp->stats.rx_packets += rx_packets;
        mgp->stats.rx_bytes += rx_bytes;
+
+       /* restock receive rings if needed */
+       if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
+               myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+                                       mgp->small_bytes + MXGEFW_PAD, 0);
+       if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
+               myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+
 }
 
 static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1484,56 +1486,48 @@ static int myri10ge_allocate_rings(struct net_device *dev)
                goto abort_with_rx_small_info;
 
        /* Fill the receive rings */
+       mgp->rx_big.cnt = 0;
+       mgp->rx_small.cnt = 0;
+       mgp->rx_big.fill_cnt = 0;
+       mgp->rx_small.fill_cnt = 0;
+       mgp->rx_small.page_offset = MYRI10GE_ALLOC_SIZE;
+       mgp->rx_big.page_offset = MYRI10GE_ALLOC_SIZE;
+       mgp->rx_small.watchdog_needed = 0;
+       mgp->rx_big.watchdog_needed = 0;
+       myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+                               mgp->small_bytes + MXGEFW_PAD, 0);
 
-       for (i = 0; i <= mgp->rx_small.mask; i++) {
-               status = myri10ge_getbuf(&mgp->rx_small, mgp,
-                                        mgp->small_bytes, i);
-               if (status) {
-                       printk(KERN_ERR
-                              "myri10ge: %s: alloced only %d small bufs\n",
-                              dev->name, i);
-                       goto abort_with_rx_small_ring;
-               }
+       if (mgp->rx_small.fill_cnt < mgp->rx_small.mask + 1) {
+               printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
+                      dev->name, mgp->rx_small.fill_cnt);
+               goto abort_with_rx_small_ring;
        }
 
-       for (i = 0; i <= mgp->rx_big.mask; i++) {
-               status =
-                   myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
-               if (status) {
-                       printk(KERN_ERR
-                              "myri10ge: %s: alloced only %d big bufs\n",
-                              dev->name, i);
-                       goto abort_with_rx_big_ring;
-               }
+       myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+       if (mgp->rx_big.fill_cnt < mgp->rx_big.mask + 1) {
+               printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
+                      dev->name, mgp->rx_big.fill_cnt);
+               goto abort_with_rx_big_ring;
        }
 
        return 0;
 
 abort_with_rx_big_ring:
-       for (i = 0; i <= mgp->rx_big.mask; i++) {
-               if (mgp->rx_big.info[i].skb != NULL)
-                       dev_kfree_skb_any(mgp->rx_big.info[i].skb);
-               if (pci_unmap_len(&mgp->rx_big.info[i], len))
-                       pci_unmap_single(mgp->pdev,
-                                        pci_unmap_addr(&mgp->rx_big.info[i],
-                                                       bus),
-                                        pci_unmap_len(&mgp->rx_big.info[i],
-                                                      len),
-                                        PCI_DMA_FROMDEVICE);
+       for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+               int idx = i & mgp->rx_big.mask;
+               myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+                                      mgp->big_bytes);
+               put_page(mgp->rx_big.info[idx].page);
        }
 
 abort_with_rx_small_ring:
-       for (i = 0; i <= mgp->rx_small.mask; i++) {
-               if (mgp->rx_small.info[i].skb != NULL)
-                       dev_kfree_skb_any(mgp->rx_small.info[i].skb);
-               if (pci_unmap_len(&mgp->rx_small.info[i], len))
-                       pci_unmap_single(mgp->pdev,
-                                        pci_unmap_addr(&mgp->rx_small.info[i],
-                                                       bus),
-                                        pci_unmap_len(&mgp->rx_small.info[i],
-                                                      len),
-                                        PCI_DMA_FROMDEVICE);
+       for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+               int idx = i & mgp->rx_small.mask;
+               myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+                                      mgp->small_bytes + MXGEFW_PAD);
+               put_page(mgp->rx_small.info[idx].page);
        }
+
        kfree(mgp->rx_big.info);
 
 abort_with_rx_small_info:
@@ -1566,30 +1560,24 @@ static void myri10ge_free_rings(struct net_device *dev)
 
        mgp = netdev_priv(dev);
 
-       for (i = 0; i <= mgp->rx_big.mask; i++) {
-               if (mgp->rx_big.info[i].skb != NULL)
-                       dev_kfree_skb_any(mgp->rx_big.info[i].skb);
-               if (pci_unmap_len(&mgp->rx_big.info[i], len))
-                       pci_unmap_single(mgp->pdev,
-                                        pci_unmap_addr(&mgp->rx_big.info[i],
-                                                       bus),
-                                        pci_unmap_len(&mgp->rx_big.info[i],
-                                                      len),
-                                        PCI_DMA_FROMDEVICE);
-       }
-
-       for (i = 0; i <= mgp->rx_small.mask; i++) {
-               if (mgp->rx_small.info[i].skb != NULL)
-                       dev_kfree_skb_any(mgp->rx_small.info[i].skb);
-               if (pci_unmap_len(&mgp->rx_small.info[i], len))
-                       pci_unmap_single(mgp->pdev,
-                                        pci_unmap_addr(&mgp->rx_small.info[i],
-                                                       bus),
-                                        pci_unmap_len(&mgp->rx_small.info[i],
-                                                      len),
-                                        PCI_DMA_FROMDEVICE);
+       for (i = mgp->rx_big.cnt; i < mgp->rx_big.fill_cnt; i++) {
+               idx = i & mgp->rx_big.mask;
+               if (i == mgp->rx_big.fill_cnt - 1)
+                       mgp->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE;
+               myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_big.info[idx],
+                                      mgp->big_bytes);
+               put_page(mgp->rx_big.info[idx].page);
        }
 
+       for (i = mgp->rx_small.cnt; i < mgp->rx_small.fill_cnt; i++) {
+               idx = i & mgp->rx_small.mask;
+               if (i == mgp->rx_small.fill_cnt - 1)
+                       mgp->rx_small.info[idx].page_offset =
+                           MYRI10GE_ALLOC_SIZE;
+               myri10ge_unmap_rx_page(mgp->pdev, &mgp->rx_small.info[idx],
+                                      mgp->small_bytes + MXGEFW_PAD);
+               put_page(mgp->rx_small.info[idx].page);
+       }
        tx = &mgp->tx;
        while (tx->done != tx->req) {
                idx = tx->done & tx->mask;
@@ -1657,19 +1645,18 @@ static int myri10ge_open(struct net_device *dev)
         */
 
        if (dev->mtu <= ETH_DATA_LEN)
-               mgp->small_bytes = 128; /* enough for a TCP header */
+               /* enough for a TCP header */
+               mgp->small_bytes = (128 > SMP_CACHE_BYTES)
+                   ? (128 - MXGEFW_PAD)
+                   : (SMP_CACHE_BYTES - MXGEFW_PAD);
        else
-               mgp->small_bytes = ETH_FRAME_LEN;       /* enough for an ETH_DATA_LEN frame */
+               /* enough for a vlan encapsulated ETH_DATA_LEN frame */
+               mgp->small_bytes = VLAN_ETH_FRAME_LEN;
 
        /* Override the small buffer size? */
        if (myri10ge_small_bytes > 0)
                mgp->small_bytes = myri10ge_small_bytes;
 
-       /* If the user sets an obscenely small MTU, adjust the small
-        * bytes down to nearly nothing */
-       if (mgp->small_bytes >= (dev->mtu + ETH_HLEN))
-               mgp->small_bytes = 64;
-
        /* get the lanai pointers to the send and receive rings */
 
        status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
@@ -1705,17 +1692,23 @@ static int myri10ge_open(struct net_device *dev)
                mgp->rx_big.wc_fifo = NULL;
        }
 
-       status = myri10ge_allocate_rings(dev);
-       if (status != 0)
-               goto abort_with_nothing;
-
        /* Firmware needs the big buff size as a power of 2.  Lie and
         * tell him the buffer is larger, because we only use 1
         * buffer/pkt, and the mtu will prevent overruns.
         */
-       big_pow2 = dev->mtu + ETH_HLEN + MXGEFW_PAD;
-       while ((big_pow2 & (big_pow2 - 1)) != 0)
-               big_pow2++;
+       big_pow2 = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
+       if (big_pow2 < MYRI10GE_ALLOC_SIZE / 2) {
+               while ((big_pow2 & (big_pow2 - 1)) != 0)
+                       big_pow2++;
+               mgp->big_bytes = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD;
+       } else {
+               big_pow2 = MYRI10GE_ALLOC_SIZE;
+               mgp->big_bytes = big_pow2;
+       }
+
+       status = myri10ge_allocate_rings(dev);
+       if (status != 0)
+               goto abort_with_nothing;
 
        /* now give firmware buffers sizes, and MTU */
        cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
@@ -2206,7 +2199,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
        struct myri10ge_cmd cmd;
        struct myri10ge_priv *mgp;
        struct dev_mc_list *mc_list;
-       __be32 data[2] = {0, 0};
+       __be32 data[2] = { 0, 0 };
        int err;
 
        mgp = netdev_priv(dev);
@@ -2625,7 +2618,7 @@ static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
 static void myri10ge_watchdog(struct work_struct *work)
 {
        struct myri10ge_priv *mgp =
-               container_of(work, struct myri10ge_priv, watchdog_work);
+           container_of(work, struct myri10ge_priv, watchdog_work);
        u32 reboot;
        int status;
        u16 cmd, vendor;
@@ -2698,6 +2691,21 @@ static void myri10ge_watchdog_timer(unsigned long arg)
        struct myri10ge_priv *mgp;
 
        mgp = (struct myri10ge_priv *)arg;
+
+       if (mgp->rx_small.watchdog_needed) {
+               myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
+                                       mgp->small_bytes + MXGEFW_PAD, 1);
+               if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt >=
+                   myri10ge_fill_thresh)
+                       mgp->rx_small.watchdog_needed = 0;
+       }
+       if (mgp->rx_big.watchdog_needed) {
+               myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 1);
+               if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt >=
+                   myri10ge_fill_thresh)
+                       mgp->rx_big.watchdog_needed = 0;
+       }
+
        if (mgp->tx.req != mgp->tx.done &&
            mgp->tx.done == mgp->watchdog_tx_done &&
            mgp->watchdog_tx_req != mgp->watchdog_tx_done)
index 9367c574477ad57d6c89b6f5d8141227eea0dd22..d2767e6584a98c320d1ac88ff1a830b5b4131149 100644 (file)
@@ -362,96 +362,6 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
 
 #define SMC_IRQ_FLAGS          (0)
 
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
 #else
 
 #define SMC_CAN_USE_8BIT       1
index 1f05511fa390f49e816d2ef77d6c12c5d68f2564..8243150f5b05ec6572cc8cfce779e7674a0b6ef0 100644 (file)
@@ -194,9 +194,9 @@ static void enqueue(struct list_head *node, struct list_head *lh)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(ugeth_lock, flags);
+       spin_lock_irqsave(&ugeth_lock, flags);
        list_add_tail(node, lh);
-       spin_unlock_irqrestore(ugeth_lock, flags);
+       spin_unlock_irqrestore(&ugeth_lock, flags);
 }
 #endif /* CONFIG_UGETH_FILTERING */
 
@@ -204,14 +204,14 @@ static struct list_head *dequeue(struct list_head *lh)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(ugeth_lock, flags);
+       spin_lock_irqsave(&ugeth_lock, flags);
        if (!list_empty(lh)) {
                struct list_head *node = lh->next;
                list_del(node);
-               spin_unlock_irqrestore(ugeth_lock, flags);
+               spin_unlock_irqrestore(&ugeth_lock, flags);
                return node;
        } else {
-               spin_unlock_irqrestore(ugeth_lock, flags);
+               spin_unlock_irqrestore(&ugeth_lock, flags);
                return NULL;
        }
 }
@@ -1852,6 +1852,8 @@ static int init_phy(struct net_device *dev)
        mii_info->mdio_read = &read_phy_reg;
        mii_info->mdio_write = &write_phy_reg;
 
+       spin_lock_init(&mii_info->mdio_lock);
+
        ugeth->mii_info = mii_info;
 
        spin_lock_irq(&ugeth->lock);
index d5ab9cf13257145eb3e43d6f508850f6228f87e6..21f76f51c95e4efd26c4466330e74a63d322f42d 100644 (file)
@@ -382,7 +382,7 @@ config SDLA
 
 # Wan router core.
 config WAN_ROUTER_DRIVERS
-       bool "WAN router drivers"
+       tristate "WAN router drivers"
        depends on WAN && WAN_ROUTER
        ---help---
          Connect LAN to WAN via Linux box.
@@ -393,7 +393,8 @@ config WAN_ROUTER_DRIVERS
          <file:Documentation/networking/wan-router.txt>.
 
          Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
+         kernel except for how subordinate drivers may be built:
+         saying N will just cause the configurator to skip all
          the questions about WAN router drivers.
 
          If unsure, say N.
index c7fa28a28b9f0b3dc31ec0f1afefc21c05654c22..36c6a1bfe558374dc76a9124375f0c06c92bfded 100644 (file)
@@ -82,9 +82,6 @@ config PARPORT_PC_PCMCIA
          Say Y here if you need PCMCIA support for your PC-style parallel
          ports. If unsure, say N.
 
-config PARPORT_NOT_PC
-       bool
-
 config PARPORT_IP32
        tristate "SGI IP32 builtin port (EXPERIMENTAL)"
        depends on SGI_IP32 && PARPORT && EXPERIMENTAL
@@ -158,5 +155,8 @@ config PARPORT_1284
          transfer modes. Also say Y if you want device ID information to
          appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N.
 
+config PARPORT_NOT_PC
+       bool
+
 endmenu
 
index 6e780db9454dfbe2e46186e24d9b01df41e25de9..adce4204d87dd7731b975504972b9c6ac8eb422c 100644 (file)
@@ -76,7 +76,8 @@ config HOTPLUG_PCI_IBM
 
 config HOTPLUG_PCI_ACPI
        tristate "ACPI PCI Hotplug driver"
-       depends on (!ACPI_DOCK && ACPI && HOTPLUG_PCI) || (ACPI_DOCK && HOTPLUG_PCI)
+       depends on HOTPLUG_PCI
+       depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
        help
          Say Y here if you have a system that supports PCI Hotplug using
          ACPI.
index b52d547b7a78e38fac23e036170e9444224090f0..8433eb7562cb2c9ceb77e365564e12de90bae8d9 100644 (file)
@@ -1 +1,2 @@
 obj-y += system-bus.o
+obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
new file mode 100644 (file)
index 0000000..6974f65
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ *  PS3 virtual uart
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 <linux/module.h>
+#include <linux/interrupt.h>
+#include <asm/ps3.h>
+
+#include <asm/lv1call.h>
+#include <asm/bitops.h>
+
+#include "vuart.h"
+
+MODULE_AUTHOR("Sony Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ps3 vuart");
+
+/**
+ * vuart - An inter-partition data link service.
+ *  port 0: PS3 AV Settings.
+ *  port 2: PS3 System Manager.
+ *
+ * The vuart provides a bi-directional byte stream data link between logical
+ * partitions.  Its primary role is as a communications link between the guest
+ * OS and the system policy module.  The current HV does not support any
+ * connections other than those listed.
+ */
+
+enum {PORT_COUNT = 3,};
+
+enum vuart_param {
+       PARAM_TX_TRIGGER = 0,
+       PARAM_RX_TRIGGER = 1,
+       PARAM_INTERRUPT_MASK = 2,
+       PARAM_RX_BUF_SIZE = 3, /* read only */
+       PARAM_RX_BYTES = 4, /* read only */
+       PARAM_TX_BUF_SIZE = 5, /* read only */
+       PARAM_TX_BYTES = 6, /* read only */
+       PARAM_INTERRUPT_STATUS = 7, /* read only */
+};
+
+enum vuart_interrupt_bit {
+       INTERRUPT_BIT_TX = 0,
+       INTERRUPT_BIT_RX = 1,
+       INTERRUPT_BIT_DISCONNECT = 2,
+};
+
+enum vuart_interrupt_mask {
+       INTERRUPT_MASK_TX = 1,
+       INTERRUPT_MASK_RX = 2,
+       INTERRUPT_MASK_DISCONNECT = 4,
+};
+
+/**
+ * struct ports_bmp - bitmap indicating ports needing service.
+ *
+ * A 256 bit read only bitmap indicating ports needing service.  Do not write
+ * to these bits.  Must not cross a page boundary.
+ */
+
+struct ports_bmp {
+       u64 status;
+       u64 unused[3];
+} __attribute__ ((aligned (32)));
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_ports_bmp(
+       const struct ports_bmp* bmp, const char* func, int line)
+{
+       pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
+}
+
+static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
+       unsigned int *port_number)
+{
+       switch(match_id) {
+       case PS3_MATCH_ID_AV_SETTINGS:
+               *port_number = 0;
+               return 0;
+       case PS3_MATCH_ID_SYSTEM_MANAGER:
+               *port_number = 2;
+               return 0;
+       default:
+               WARN_ON(1);
+               *port_number = UINT_MAX;
+               return -EINVAL;
+       };
+}
+
+#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
+       const char* func, int line)
+{
+#if defined(DEBUG)
+       static const char *strings[] = {
+               "tx_trigger      ",
+               "rx_trigger      ",
+               "interrupt_mask  ",
+               "rx_buf_size     ",
+               "rx_bytes        ",
+               "tx_buf_size     ",
+               "tx_bytes        ",
+               "interrupt_status",
+       };
+       int result;
+       unsigned int i;
+       u64 value;
+
+       for (i = 0; i < ARRAY_SIZE(strings); i++) {
+               result = lv1_get_virtual_uart_param(port_number, i, &value);
+
+               if (result) {
+                       pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
+                               port_number, strings[i], ps3_result(result));
+                       continue;
+               }
+               pr_debug("%s:%d: port_%u: %s = %lxh\n",
+                       func, line, port_number, strings[i], value);
+       }
+#endif
+}
+
+struct vuart_triggers {
+       unsigned long rx;
+       unsigned long tx;
+};
+
+int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
+       struct vuart_triggers *trig)
+{
+       int result;
+       unsigned long size;
+       unsigned long val;
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_TX_TRIGGER, &trig->tx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BUF_SIZE, &size);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_TRIGGER, &val);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       trig->rx = size - val;
+
+       dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
+               trig->tx, trig->rx);
+
+       return result;
+}
+
+int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
+       unsigned int rx)
+{
+       int result;
+       unsigned long size;
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_TX_TRIGGER, tx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BUF_SIZE, &size);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_RX_TRIGGER, size - rx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
+               tx, rx);
+
+       return result;
+}
+
+static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
+       unsigned long *bytes_waiting)
+{
+       int result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BYTES, bytes_waiting);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
+               *bytes_waiting);
+       return result;
+}
+
+static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
+       unsigned long mask)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
+
+       dev->interrupt_mask = mask;
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_INTERRUPT_MASK, dev->interrupt_mask);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       return result;
+}
+
+static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
+       unsigned long *status)
+{
+       int result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_INTERRUPT_STATUS, status);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
+               __func__, __LINE__, dev->interrupt_mask, *status,
+               dev->interrupt_mask & *status);
+
+       return result;
+}
+
+int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_TX);
+}
+
+int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_RX);
+}
+
+int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_DISCONNECT);
+}
+
+int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_TX)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_TX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_RX)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_RX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_DISCONNECT) : 0;
+}
+
+/**
+ * ps3_vuart_raw_write - Low level write helper.
+ *
+ * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
+ */
+
+static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
+       const void* buf, unsigned int bytes, unsigned long *bytes_written)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+       result = lv1_write_virtual_uart(dev->port_number,
+               ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
+                       "%s\n", __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev->stats.bytes_written += *bytes_written;
+
+       dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
+               __LINE__, *bytes_written, bytes, dev->stats.bytes_written);
+
+       return result;
+}
+
+/**
+ * ps3_vuart_raw_read - Low level read helper.
+ *
+ * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
+ */
+
+static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes, unsigned long *bytes_read)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+       result = lv1_read_virtual_uart(dev->port_number,
+               ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev->stats.bytes_read += *bytes_read;
+
+       dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
+               *bytes_read, bytes, dev->stats.bytes_read);
+
+       return result;
+}
+
+/**
+ * struct list_buffer - An element for a port device fifo buffer list.
+ */
+
+struct list_buffer {
+       struct list_head link;
+       const unsigned char *head;
+       const unsigned char *tail;
+       unsigned long dbg_number;
+       unsigned char data[];
+};
+
+/**
+ * ps3_vuart_write - the entry point for writing data to a port
+ *
+ * If the port is idle on entry as much of the incoming data is written to
+ * the port as the port will accept.  Otherwise a list buffer is created
+ * and any remaning incoming data is copied to that buffer.  The buffer is
+ * then enqueued for transmision via the transmit interrupt.
+ */
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+       unsigned int bytes)
+{
+       static unsigned long dbg_number;
+       int result;
+       unsigned long flags;
+       struct list_buffer *lb;
+
+       dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+               bytes, bytes);
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+       if (list_empty(&dev->tx_list.head)) {
+               unsigned long bytes_written;
+
+               result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
+
+               spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_vuart_raw_write failed\n",
+                               __func__, __LINE__);
+                       return result;
+               }
+
+               if (bytes_written == bytes) {
+                       dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
+                               __func__, __LINE__, bytes);
+                       return 0;
+               }
+
+               bytes -= bytes_written;
+               buf += bytes_written;
+       } else
+               spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+       lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
+
+       if (!lb) {
+               return -ENOMEM;
+       }
+
+       memcpy(lb->data, buf, bytes);
+       lb->head = lb->data;
+       lb->tail = lb->data + bytes;
+       lb->dbg_number = ++dbg_number;
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+       list_add_tail(&lb->link, &dev->tx_list.head);
+       ps3_vuart_enable_interrupt_tx(dev);
+       spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+/**
+ * ps3_vuart_read - the entry point for reading data from a port
+ *
+ * If enough bytes to satisfy the request are held in the buffer list those
+ * bytes are dequeued and copied to the caller's buffer.  Emptied list buffers
+ * are retiered.  If the request cannot be statified by bytes held in the list
+ * buffers -EAGAIN is returned.
+ */
+
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes)
+{
+       unsigned long flags;
+       struct list_buffer *lb, *n;
+       unsigned long bytes_read;
+
+       dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+               bytes, bytes);
+
+       spin_lock_irqsave(&dev->rx_list.lock, flags);
+
+       if (dev->rx_list.bytes_held < bytes) {
+               spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+               dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
+                       __func__, __LINE__, bytes - dev->rx_list.bytes_held);
+               return -EAGAIN;
+       }
+
+       list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
+               bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
+
+               memcpy(buf, lb->head, bytes_read);
+               buf += bytes_read;
+               bytes -= bytes_read;
+               dev->rx_list.bytes_held -= bytes_read;
+
+               if (bytes_read < lb->tail - lb->head) {
+                       lb->head += bytes_read;
+                       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+                       dev_dbg(&dev->core,
+                               "%s:%d: dequeued buf_%lu, %lxh bytes\n",
+                               __func__, __LINE__, lb->dbg_number, bytes_read);
+                       return 0;
+               }
+
+               dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+                       lb->dbg_number);
+
+               list_del(&lb->link);
+               kfree(lb);
+       }
+       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
+ *
+ * Services the transmit interrupt for the port.  Writes as much data from the
+ * buffer list as the port will accept.  Retires any emptied list buffers and
+ * adjusts the final list buffer state for a partial write.
+ */
+
+static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       int result = 0;
+       unsigned long flags;
+       struct list_buffer *lb, *n;
+       unsigned long bytes_total = 0;
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+       list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
+
+               unsigned long bytes_written;
+
+               result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
+                       &bytes_written);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_vuart_raw_write failed\n",
+                               __func__, __LINE__);
+                       break;
+               }
+
+               bytes_total += bytes_written;
+
+               if (bytes_written < lb->tail - lb->head) {
+                       lb->head += bytes_written;
+                       dev_dbg(&dev->core,
+                               "%s:%d cleared buf_%lu, %lxh bytes\n",
+                               __func__, __LINE__, lb->dbg_number,
+                               bytes_written);
+                       goto port_full;
+               }
+
+               dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+                       lb->dbg_number);
+
+               list_del(&lb->link);
+               kfree(lb);
+       }
+
+       ps3_vuart_disable_interrupt_tx(dev);
+port_full:
+       spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+       dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
+               __func__, __LINE__, bytes_total);
+       return result;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
+ *
+ * Services the receive interrupt for the port.  Creates a list buffer and
+ * copies all waiting port data to that buffer and enqueues the buffer in the
+ * buffer list.  Buffer list data is dequeued via ps3_vuart_read.
+ */
+
+static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       static unsigned long dbg_number;
+       int result = 0;
+       unsigned long flags;
+       struct list_buffer *lb;
+       unsigned long bytes;
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
+
+       if (result)
+               return -EIO;
+
+       BUG_ON(!bytes);
+
+       /* add some extra space for recently arrived data */
+
+       bytes += 128;
+
+       lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
+
+       if (!lb)
+               return -ENOMEM;
+
+       ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
+
+       lb->head = lb->data;
+       lb->tail = lb->data + bytes;
+       lb->dbg_number = ++dbg_number;
+
+       spin_lock_irqsave(&dev->rx_list.lock, flags);
+       list_add_tail(&lb->link, &dev->rx_list.head);
+       dev->rx_list.bytes_held += bytes;
+       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+static int ps3_vuart_handle_interrupt_disconnect(
+       struct ps3_vuart_port_device *dev)
+{
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+       BUG_ON("no support");
+       return -1;
+}
+
+/**
+ * ps3_vuart_handle_port_interrupt - second stage interrupt handler
+ *
+ * Services any pending interrupt types for the port.  Passes control to the
+ * third stage type specific interrupt handler.  Returns control to the first
+ * stage handler after one iteration.
+ */
+
+static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
+{
+       int result;
+       unsigned long status;
+
+       result = ps3_vuart_get_interrupt_mask(dev, &status);
+
+       if (result)
+               return result;
+
+       dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
+               status);
+
+       if (status & INTERRUPT_MASK_DISCONNECT) {
+               dev->stats.disconnect_interrupts++;
+               result = ps3_vuart_handle_interrupt_disconnect(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_disconnect(dev);
+       }
+
+       if (status & INTERRUPT_MASK_TX) {
+               dev->stats.tx_interrupts++;
+               result = ps3_vuart_handle_interrupt_tx(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_tx(dev);
+       }
+
+       if (status & INTERRUPT_MASK_RX) {
+               dev->stats.rx_interrupts++;
+               result = ps3_vuart_handle_interrupt_rx(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_rx(dev);
+       }
+
+       return 0;
+}
+
+struct vuart_private {
+       unsigned int in_use;
+       unsigned int virq;
+       struct ps3_vuart_port_device *devices[PORT_COUNT];
+       const struct ports_bmp bmp;
+};
+
+/**
+ * ps3_vuart_irq_handler - first stage interrupt handler
+ *
+ * Loops finding any interrupting port and its associated instance data.
+ * Passes control to the second stage port specific interrupt handler.  Loops
+ * until all outstanding interrupts are serviced.
+ */
+
+static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
+{
+       struct vuart_private *private;
+
+       BUG_ON(!_private);
+       private = (struct vuart_private *)_private;
+
+       while (1) {
+               unsigned int port;
+
+               dump_ports_bmp(&private->bmp);
+
+               port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
+
+               if (port == BITS_PER_LONG)
+                       break;
+
+               BUG_ON(port >= PORT_COUNT);
+               BUG_ON(!private->devices[port]);
+
+               ps3_vuart_handle_port_interrupt(private->devices[port]);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
+{
+       int result;
+       struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+
+       result = dev->match_id == drv->match_id;
+
+       dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
+               __LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
+               drv->core.name, (result ? "match" : "miss"));
+
+       return result;
+}
+
+static struct vuart_private vuart_private;
+
+static int ps3_vuart_probe(struct device *_dev)
+{
+       int result;
+       unsigned long tmp;
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+       struct ps3_vuart_port_driver *drv =
+               to_ps3_vuart_port_driver(_dev->driver);
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       BUG_ON(!drv);
+
+       result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
+                       __func__, __LINE__, dev->match_id);
+               result = -EINVAL;
+               goto fail_match;
+       }
+
+       if (vuart_private.devices[dev->port_number]) {
+               dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
+                       __LINE__, dev->port_number);
+               result = -EBUSY;
+               goto fail_match;
+       }
+
+       vuart_private.devices[dev->port_number] = dev;
+
+       INIT_LIST_HEAD(&dev->tx_list.head);
+       spin_lock_init(&dev->tx_list.lock);
+       INIT_LIST_HEAD(&dev->rx_list.head);
+       spin_lock_init(&dev->rx_list.lock);
+
+       vuart_private.in_use++;
+       if (vuart_private.in_use == 1) {
+               result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
+                       &vuart_private.virq);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+                               __func__, __LINE__, result);
+                       result = -EPERM;
+                       goto fail_alloc_irq;
+               }
+
+               result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
+                       IRQF_DISABLED, "vuart", &vuart_private);
+
+               if (result) {
+                       dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
+                               __func__, __LINE__, result);
+                       goto fail_request_irq;
+               }
+       }
+
+       ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
+
+       /* clear stale pending interrupts */
+       ps3_vuart_get_interrupt_mask(dev, &tmp);
+
+       ps3_vuart_set_triggers(dev, 1, 1);
+
+       if (drv->probe)
+               result = drv->probe(dev);
+       else {
+               result = 0;
+               dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
+                       __LINE__);
+       }
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
+                       __func__, __LINE__);
+               goto fail_probe;
+       }
+
+       return result;
+
+fail_probe:
+fail_request_irq:
+       vuart_private.in_use--;
+       if (!vuart_private.in_use) {
+               ps3_free_vuart_irq(vuart_private.virq);
+               vuart_private.virq = NO_IRQ;
+       }
+fail_alloc_irq:
+fail_match:
+       dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
+       return result;
+}
+
+static int ps3_vuart_remove(struct device *_dev)
+{
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+       struct ps3_vuart_port_driver *drv =
+               to_ps3_vuart_port_driver(_dev->driver);
+
+       dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
+               dev->core.bus_id);
+
+       BUG_ON(vuart_private.in_use < 1);
+
+       if (drv->remove)
+               drv->remove(dev);
+       else
+               dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
+                       __LINE__, dev->core.bus_id);
+
+       vuart_private.in_use--;
+
+       if (!vuart_private.in_use) {
+               free_irq(vuart_private.virq, &vuart_private);
+               ps3_free_vuart_irq(vuart_private.virq);
+               vuart_private.virq = NO_IRQ;
+       }
+       return 0;
+}
+
+/**
+ * ps3_vuart - The vuart instance.
+ *
+ * The vuart is managed as a bus that port devices connect to.
+ */
+
+struct bus_type ps3_vuart = {
+        .name = "ps3_vuart",
+       .match = ps3_vuart_match,
+       .probe = ps3_vuart_probe,
+       .remove = ps3_vuart_remove,
+};
+
+int __init ps3_vuart_init(void)
+{
+       int result;
+
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       result = bus_register(&ps3_vuart);
+       BUG_ON(result);
+       return result;
+}
+
+void __exit ps3_vuart_exit(void)
+{
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       bus_unregister(&ps3_vuart);
+}
+
+core_initcall(ps3_vuart_init);
+module_exit(ps3_vuart_exit);
+
+/**
+ * ps3_vuart_port_release_device - Remove a vuart port device.
+ */
+
+static void ps3_vuart_port_release_device(struct device *_dev)
+{
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+#if defined(DEBUG)
+       memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
+#endif
+       kfree(dev);
+}
+
+/**
+ * ps3_vuart_port_device_register - Add a vuart port device.
+ */
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
+{
+       int result;
+       static unsigned int dev_count = 1;
+
+       dev->core.parent = NULL;
+       dev->core.bus = &ps3_vuart;
+       dev->core.release = ps3_vuart_port_release_device;
+
+       snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
+               dev_count++);
+
+       dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
+
+       result = device_register(&dev->core);
+
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
+
+/**
+ * ps3_vuart_port_driver_register - Add a vuart port device driver.
+ */
+
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
+{
+       int result;
+
+       pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
+       drv->core.bus = &ps3_vuart;
+       result = driver_register(&drv->core);
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
+
+/**
+ * ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
+ */
+
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
+{
+       driver_unregister(&drv->core);
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
new file mode 100644 (file)
index 0000000..28fd89f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  PS3 virtual uart
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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
+ */
+
+#if !defined(_PS3_VUART_H)
+#define _PS3_VUART_H
+
+struct ps3_vuart_stats {
+       unsigned long bytes_written;
+       unsigned long bytes_read;
+       unsigned long tx_interrupts;
+       unsigned long rx_interrupts;
+       unsigned long disconnect_interrupts;
+};
+
+/**
+ * struct ps3_vuart_port_device - a device on a vuart port
+ */
+
+struct ps3_vuart_port_device {
+       enum ps3_match_id match_id;
+       struct device core;
+
+       /* private driver variables */
+       unsigned int port_number;
+       unsigned long interrupt_mask;
+       struct {
+               spinlock_t lock;
+               struct list_head head;
+       } tx_list;
+       struct {
+               unsigned long bytes_held;
+               spinlock_t lock;
+               struct list_head head;
+       } rx_list;
+       struct ps3_vuart_stats stats;
+};
+
+/**
+ * struct ps3_vuart_port_driver - a driver for a device on a vuart port
+ */
+
+struct ps3_vuart_port_driver {
+       enum ps3_match_id match_id;
+       struct device_driver core;
+       int (*probe)(struct ps3_vuart_port_device *);
+       int (*remove)(struct ps3_vuart_port_device *);
+       int (*tx_event)(struct ps3_vuart_port_device *dev);
+       int (*rx_event)(struct ps3_vuart_port_device *dev);
+       int (*disconnect_event)(struct ps3_vuart_port_device *dev);
+       /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
+       /* int (*resume)(struct ps3_vuart_port_device *); */
+};
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
+int ps3_vuart_write(struct ps3_vuart_port_device *dev,
+       const void* buf, unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes);
+static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
+       struct device_driver *_drv)
+{
+       return container_of(_drv, struct ps3_vuart_port_driver, core);
+}
+static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
+       struct device *_dev)
+{
+       return container_of(_dev, struct ps3_vuart_port_device, core);
+}
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+       unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes);
+
+#endif
index 2a63ab2b47f4a11b4f07681f7111b96500267de9..09660e2ab051d6d9e9a313686fc894ca4cbfe6e3 100644 (file)
@@ -288,7 +288,7 @@ config RTC_DRV_PL031
          To compile this driver as a module, choose M here: the
          module will be called rtc-pl031.
 
-config RTC_DRV_AT91
+config RTC_DRV_AT91RM9200
        tristate "AT91RM9200"
        depends on RTC_CLASS && ARCH_AT91RM9200
        help
index bd4c45d333f07aff1d0a8bb79ba2750520994362..e6beedacc96614ad329b82a9167d2e7b989e5de2 100644 (file)
@@ -35,5 +35,5 @@ obj-$(CONFIG_RTC_DRV_VR41XX)  += rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
-obj-$(CONFIG_RTC_DRV_AT91)     += rtc-at91.o
+obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_SH)       += rtc-sh.o
index dfef1637bfb8a1a69dc1848d75e2b490a458ddaf..205fa28593b769820f966ec25e5f122a6745bdaa 100644 (file)
@@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
        struct i2c_client *client;
        struct rtc_device *rtc;
 
-       dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+       dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
index ba795a4db1e97289829c3c69dbee613fa2720a25..7bbc26a34bd25d7007abaaea57d017343f24ce59 100644 (file)
@@ -117,4 +117,85 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
 }
 EXPORT_SYMBOL(rtc_tm_to_time);
 
+
+/* Merge the valid (i.e. non-negative) fields of alarm into the current
+ * time.  If the valid alarm fields are earlier than the equivalent
+ * fields in the time, carry one into the least significant invalid
+ * field, so that the alarm expiry is in the future.  It assumes that the
+ * least significant invalid field is more significant than the most
+ * significant valid field, and that the seconds field is valid.
+ *
+ * This is used by alarms that take relative (rather than absolute)
+ * times, and/or have a simple binary second counter instead of
+ * day/hour/minute/sec registers.
+ */
+void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm)
+{
+       int *alarmp = &alarm->tm_sec;
+       int *timep = &now->tm_sec;
+       int carry_into, i;
+
+       /* Ignore everything past the 6th element (tm_year). */
+       for (i = 5; i > 0; i--) {
+               if (alarmp[i] < 0)
+                       alarmp[i] = timep[i];
+               else
+                       break;
+       }
+
+       /* No carry needed if all fields are valid. */
+       if (i == 5)
+               return;
+
+       for (carry_into = i + 1; i >= 0; i--) {
+               if (alarmp[i] < timep[i])
+                       break;
+
+               if (alarmp[i] > timep[i])
+                       return;
+       }
+
+       switch (carry_into) {
+               case 1:
+                       alarm->tm_min++;
+
+                       if (alarm->tm_min < 60)
+                               return;
+
+                       alarm->tm_min = 0;
+                       /* fall-through */
+
+               case 2:
+                       alarm->tm_hour++;
+
+                       if (alarm->tm_hour < 60)
+                               return;
+
+                       alarm->tm_hour = 0;
+                       /* fall-through */
+
+               case 3:
+                       alarm->tm_mday++;
+
+                       if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon])
+                               return;
+
+                       alarm->tm_mday = 1;
+                       /* fall-through */
+
+               case 4:
+                       alarm->tm_mon++;
+
+                       if (alarm->tm_mon <= 12)
+                               return;
+
+                       alarm->tm_mon = 1;
+                       /* fall-through */
+
+               case 5:
+                       alarm->tm_year++;
+       }
+}
+EXPORT_SYMBOL(rtc_merge_alarm);
+
 MODULE_LICENSE("GPL");
index a760cf69af90de24bb80782fbdbf3a393d08777c..4b72b8ef5d66feee8e6ab70a9a0f635d80a35376 100644 (file)
@@ -192,7 +192,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
                xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
 
                if (xfer != ARRAY_SIZE(msgs)) {
-                       dev_err(&client->adapter->dev,
+                       dev_err(&client->dev,
                                "%s: could not read register 0x%02X\n",
                                __FUNCTION__, pattern[i].reg);
 
@@ -203,7 +203,7 @@ static int pcf8563_validate_client(struct i2c_client *client)
 
                if (value > pattern[i].max ||
                        value < pattern[i].min) {
-                       dev_dbg(&client->adapter->dev,
+                       dev_dbg(&client->dev,
                                "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
                                "max=%d, value=%d, raw=0x%02X\n",
                                __FUNCTION__, i, pattern[i].reg, pattern[i].mask,
@@ -253,7 +253,7 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
 
        int err = 0;
 
-       dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+       dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
index e2c7698fdba312c5b759df934d25375bd1c143be..1460f6b769f2e92975206485bedc9da19be2625e 100644 (file)
@@ -200,7 +200,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
        struct i2c_client *client;
        struct rs5c372 *rs5c372;
 
-       dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+       dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
index 143302a8e79c5ed283a86b960850aa753014592e..72ba1a70f35f6def6e9468c5fd9a5f70cb5216a0 100644 (file)
@@ -2,6 +2,7 @@
  * SuperH On-Chip RTC Support
  *
  * Copyright (C) 2006  Paul Mundt
+ * Copyright (C) 2006  Jamie Lenehan
  *
  * Based on the old arch/sh/kernel/cpu/rtc.c by:
  *
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
+
+#define DRV_NAME       "sh-rtc"
+#define DRV_VERSION    "0.1.2"
 
 #ifdef CONFIG_CPU_SH3
 #define rtc_reg_size           sizeof(u16)
 
 #define RTC_REG(r)     ((r) * rtc_reg_size)
 
-#define R64CNT         RTC_REG(0)
-#define RSECCNT        RTC_REG(1)
-#define RMINCNT        RTC_REG(2)
-#define RHRCNT         RTC_REG(3)
-#define RWKCNT         RTC_REG(4)
-#define RDAYCNT        RTC_REG(5)
-#define RMONCNT        RTC_REG(6)
-#define RYRCNT         RTC_REG(7)
-#define RSECAR         RTC_REG(8)
-#define RMINAR         RTC_REG(9)
-#define RHRAR          RTC_REG(10)
-#define RWKAR          RTC_REG(11)
-#define RDAYAR         RTC_REG(12)
-#define RMONAR         RTC_REG(13)
-#define RCR1           RTC_REG(14)
-#define RCR2           RTC_REG(15)
+#define R64CNT         RTC_REG(0)
+
+#define RSECCNT                RTC_REG(1)      /* RTC sec */
+#define RMINCNT                RTC_REG(2)      /* RTC min */
+#define RHRCNT         RTC_REG(3)      /* RTC hour */
+#define RWKCNT         RTC_REG(4)      /* RTC week */
+#define RDAYCNT                RTC_REG(5)      /* RTC day */
+#define RMONCNT                RTC_REG(6)      /* RTC month */
+#define RYRCNT         RTC_REG(7)      /* RTC year */
+#define RSECAR         RTC_REG(8)      /* ALARM sec */
+#define RMINAR         RTC_REG(9)      /* ALARM min */
+#define RHRAR          RTC_REG(10)     /* ALARM hour */
+#define RWKAR          RTC_REG(11)     /* ALARM week */
+#define RDAYAR         RTC_REG(12)     /* ALARM day */
+#define RMONAR         RTC_REG(13)     /* ALARM month */
+#define RCR1           RTC_REG(14)     /* Control */
+#define RCR2           RTC_REG(15)     /* Control */
+
+/* ALARM Bits - or with BCD encoded value */
+#define AR_ENB         0x80    /* Enable for alarm cmp   */
 
 /* RCR1 Bits */
 #define RCR1_CF                0x80    /* Carry Flag             */
@@ -71,22 +79,28 @@ struct sh_rtc {
        unsigned int alarm_irq, periodic_irq, carry_irq;
        struct rtc_device *rtc_dev;
        spinlock_t lock;
+       int rearm_aie;
 };
 
-static irqreturn_t sh_rtc_interrupt(int irq, void *id)
+static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
 {
-       struct platform_device *pdev = id;
+       struct platform_device *pdev = to_platform_device(dev_id);
        struct sh_rtc *rtc = platform_get_drvdata(pdev);
        unsigned int tmp, events = 0;
 
        spin_lock(&rtc->lock);
 
        tmp = readb(rtc->regbase + RCR1);
+       tmp &= ~RCR1_CF;
 
-       if (tmp & RCR1_AF)
-               events |= RTC_AF | RTC_IRQF;
-
-       tmp &= ~(RCR1_CF | RCR1_AF);
+       if (rtc->rearm_aie) {
+               if (tmp & RCR1_AF)
+                       tmp &= ~RCR1_AF;        /* try to clear AF again */
+               else {
+                       tmp |= RCR1_AIE;        /* AF has cleared, rearm IRQ */
+                       rtc->rearm_aie = 0;
+               }
+       }
 
        writeb(tmp, rtc->regbase + RCR1);
 
@@ -97,9 +111,45 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *id)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t sh_rtc_periodic(int irq, void *id)
+static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
+{
+       struct platform_device *pdev = to_platform_device(dev_id);
+       struct sh_rtc *rtc = platform_get_drvdata(pdev);
+       unsigned int tmp, events = 0;
+
+       spin_lock(&rtc->lock);
+
+       tmp = readb(rtc->regbase + RCR1);
+
+       /*
+        * If AF is set then the alarm has triggered. If we clear AF while
+        * the alarm time still matches the RTC time then AF will
+        * immediately be set again, and if AIE is enabled then the alarm
+        * interrupt will immediately be retrigger. So we clear AIE here
+        * and use rtc->rearm_aie so that the carry interrupt will keep
+        * trying to clear AF and once it stays cleared it'll re-enable
+        * AIE.
+        */
+       if (tmp & RCR1_AF) {
+               events |= RTC_AF | RTC_IRQF;
+
+               tmp &= ~(RCR1_AF|RCR1_AIE);
+
+               writeb(tmp, rtc->regbase + RCR1);
+
+               rtc->rearm_aie = 1;
+
+               rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+       }
+
+       spin_unlock(&rtc->lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
 {
-       struct sh_rtc *rtc = dev_get_drvdata(id);
+       struct platform_device *pdev = to_platform_device(dev_id);
+       struct sh_rtc *rtc = platform_get_drvdata(pdev);
 
        spin_lock(&rtc->lock);
 
@@ -139,10 +189,11 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
 
        tmp = readb(rtc->regbase + RCR1);
 
-       if (enable)
-               tmp |= RCR1_AIE;
-       else
+       if (!enable) {
                tmp &= ~RCR1_AIE;
+               rtc->rearm_aie = 0;
+       } else if (rtc->rearm_aie == 0)
+               tmp |= RCR1_AIE;
 
        writeb(tmp, rtc->regbase + RCR1);
 
@@ -177,7 +228,7 @@ static int sh_rtc_open(struct device *dev)
                goto err_bad_carry;
        }
 
-       ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED,
+       ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
                          "sh-rtc alarm", dev);
        if (unlikely(ret)) {
                dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
@@ -200,6 +251,7 @@ static void sh_rtc_release(struct device *dev)
        struct sh_rtc *rtc = dev_get_drvdata(dev);
 
        sh_rtc_setpie(dev, 0);
+       sh_rtc_setaie(dev, 0);
 
        free_irq(rtc->periodic_irq, dev);
        free_irq(rtc->carry_irq, dev);
@@ -267,7 +319,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_hour     = BCD2BIN(readb(rtc->regbase + RHRCNT));
                tm->tm_wday     = BCD2BIN(readb(rtc->regbase + RWKCNT));
                tm->tm_mday     = BCD2BIN(readb(rtc->regbase + RDAYCNT));
-               tm->tm_mon      = BCD2BIN(readb(rtc->regbase + RMONCNT));
+               tm->tm_mon      = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
 
 #if defined(CONFIG_CPU_SH4)
                yr  = readw(rtc->regbase + RYRCNT);
@@ -295,7 +347,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                "mday=%d, mon=%d, year=%d, wday=%d\n",
                __FUNCTION__,
                tm->tm_sec, tm->tm_min, tm->tm_hour,
-               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+               tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
 
        if (rtc_valid_tm(tm) < 0)
                dev_err(dev, "invalid date\n");
@@ -322,7 +374,7 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
        writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
        writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
        writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
-       writeb(BIN2BCD(tm->tm_mon),  rtc->regbase + RMONCNT);
+       writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
 
 #ifdef CONFIG_CPU_SH3
        year = tm->tm_year % 100;
@@ -344,12 +396,136 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return 0;
 }
 
+static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off)
+{
+       unsigned int byte;
+       int value = 0xff;       /* return 0xff for ignored values */
+
+       byte = readb(rtc->regbase + reg_off);
+       if (byte & AR_ENB) {
+               byte &= ~AR_ENB;        /* strip the enable bit */
+               value = BCD2BIN(byte);
+       }
+
+       return value;
+}
+
+static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_rtc *rtc = platform_get_drvdata(pdev);
+       struct rtc_time* tm = &wkalrm->time;
+
+       spin_lock_irq(&rtc->lock);
+
+       tm->tm_sec      = sh_rtc_read_alarm_value(rtc, RSECAR);
+       tm->tm_min      = sh_rtc_read_alarm_value(rtc, RMINAR);
+       tm->tm_hour     = sh_rtc_read_alarm_value(rtc, RHRAR);
+       tm->tm_wday     = sh_rtc_read_alarm_value(rtc, RWKAR);
+       tm->tm_mday     = sh_rtc_read_alarm_value(rtc, RDAYAR);
+       tm->tm_mon      = sh_rtc_read_alarm_value(rtc, RMONAR);
+       if (tm->tm_mon > 0)
+               tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
+       tm->tm_year     = 0xffff;
+
+       spin_unlock_irq(&rtc->lock);
+
+       return 0;
+}
+
+static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
+                                           int value, int reg_off)
+{
+       /* < 0 for a value that is ignored */
+       if (value < 0)
+               writeb(0, rtc->regbase + reg_off);
+       else
+               writeb(BIN2BCD(value) | AR_ENB,  rtc->regbase + reg_off);
+}
+
+static int sh_rtc_check_alarm(struct rtc_time* tm)
+{
+       /*
+        * The original rtc says anything > 0xc0 is "don't care" or "match
+        * all" - most users use 0xff but rtc-dev uses -1 for the same thing.
+        * The original rtc doesn't support years - some things use -1 and
+        * some 0xffff. We use -1 to make out tests easier.
+        */
+       if (tm->tm_year == 0xffff)
+               tm->tm_year = -1;
+       if (tm->tm_mon >= 0xff)
+               tm->tm_mon = -1;
+       if (tm->tm_mday >= 0xff)
+               tm->tm_mday = -1;
+       if (tm->tm_wday >= 0xff)
+               tm->tm_wday = -1;
+       if (tm->tm_hour >= 0xff)
+               tm->tm_hour = -1;
+       if (tm->tm_min >= 0xff)
+               tm->tm_min = -1;
+       if (tm->tm_sec >= 0xff)
+               tm->tm_sec = -1;
+
+       if (tm->tm_year > 9999 ||
+               tm->tm_mon >= 12 ||
+               tm->tm_mday == 0 || tm->tm_mday >= 32 ||
+               tm->tm_wday >= 7 ||
+               tm->tm_hour >= 24 ||
+               tm->tm_min >= 60 ||
+               tm->tm_sec >= 60)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_rtc *rtc = platform_get_drvdata(pdev);
+       unsigned int rcr1;
+       struct rtc_time *tm = &wkalrm->time;
+       int mon, err;
+
+       err = sh_rtc_check_alarm(tm);
+       if (unlikely(err < 0))
+               return err;
+
+       spin_lock_irq(&rtc->lock);
+
+       /* disable alarm interrupt and clear flag */
+       rcr1 = readb(rtc->regbase + RCR1);
+       rcr1 &= ~RCR1_AF;
+       writeb(rcr1 & ~RCR1_AIE, rtc->regbase + RCR1);
+
+       rtc->rearm_aie = 0;
+
+       /* set alarm time */
+       sh_rtc_write_alarm_value(rtc, tm->tm_sec,  RSECAR);
+       sh_rtc_write_alarm_value(rtc, tm->tm_min,  RMINAR);
+       sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR);
+       sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR);
+       sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR);
+       mon = tm->tm_mon;
+       if (mon >= 0)
+               mon += 1;
+       sh_rtc_write_alarm_value(rtc, mon, RMONAR);
+
+       /* Restore interrupt activation status */
+       writeb(rcr1, rtc->regbase + RCR1);
+
+       spin_unlock_irq(&rtc->lock);
+
+       return 0;
+}
+
 static struct rtc_class_ops sh_rtc_ops = {
        .open           = sh_rtc_open,
        .release        = sh_rtc_release,
        .ioctl          = sh_rtc_ioctl,
        .read_time      = sh_rtc_read_time,
        .set_time       = sh_rtc_set_time,
+       .read_alarm     = sh_rtc_read_alarm,
+       .set_alarm      = sh_rtc_set_alarm,
        .proc           = sh_rtc_proc,
 };
 
@@ -442,7 +618,7 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev)
 }
 static struct platform_driver sh_rtc_platform_driver = {
        .driver         = {
-               .name   = "sh-rtc",
+               .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
        .probe          = sh_rtc_probe,
@@ -463,5 +639,6 @@ module_init(sh_rtc_init);
 module_exit(sh_rtc_exit);
 
 MODULE_DESCRIPTION("SuperH on-chip RTC driver");
-MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, Jamie Lenehan <lenehan@twibble.org>");
 MODULE_LICENSE("GPL");
index 9a67487d086ba55ab36e202c1e7bbc9f9cf1239d..019ae255b0c8b2d143aae18a6d5ebbdb05b135d2 100644 (file)
@@ -372,7 +372,7 @@ static int x1205_validate_client(struct i2c_client *client)
                };
 
                if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
-                       dev_err(&client->adapter->dev,
+                       dev_err(&client->dev,
                                "%s: could not read register %x\n",
                                __FUNCTION__, probe_zero_pattern[i]);
 
@@ -380,7 +380,7 @@ static int x1205_validate_client(struct i2c_client *client)
                }
 
                if ((buf & probe_zero_pattern[i+1]) != 0) {
-                       dev_err(&client->adapter->dev,
+                       dev_err(&client->dev,
                                "%s: register=%02x, zero pattern=%d, value=%x\n",
                                __FUNCTION__, probe_zero_pattern[i], i, buf);
 
@@ -400,7 +400,7 @@ static int x1205_validate_client(struct i2c_client *client)
                };
 
                if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
-                       dev_err(&client->adapter->dev,
+                       dev_err(&client->dev,
                                "%s: could not read register %x\n",
                                __FUNCTION__, probe_limits_pattern[i].reg);
 
@@ -411,7 +411,7 @@ static int x1205_validate_client(struct i2c_client *client)
 
                if (value > probe_limits_pattern[i].max ||
                        value < probe_limits_pattern[i].min) {
-                       dev_dbg(&client->adapter->dev,
+                       dev_dbg(&client->dev,
                                "%s: register=%x, lim pattern=%d, value=%d\n",
                                __FUNCTION__, probe_limits_pattern[i].reg,
                                i, value);
@@ -506,7 +506,7 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
        struct i2c_client *client;
        struct rtc_device *rtc;
 
-       dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+       dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
index fc12d5df10e2175f3c6346c7a371ca79da8c6780..0b36dd5cdac2c4741b2919247015b8640f54e9c7 100644 (file)
@@ -151,32 +151,6 @@ config SERIAL_8250_MANY_PORTS
          say N here to save some memory. You can also say Y if you have an
          "intelligent" multiport card such as Cyclades, Digiboards, etc.
 
-config SERIAL_8250_SHARE_IRQ
-       bool "Support for sharing serial interrupts"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Some serial boards have hardware support which allows multiple dumb
-         serial ports on the same board to share a single IRQ. To enable
-         support for this in the serial driver, say Y here.
-
-config SERIAL_8250_DETECT_IRQ
-       bool "Autodetect IRQ on standard ports (unsafe)"
-       depends on SERIAL_8250_EXTENDED
-       help
-         Say Y here if you want the kernel to try to guess which IRQ
-         to use for your serial port.
-
-         This is considered unsafe; it is far better to configure the IRQ in
-         a boot script using the setserial command.
-
-         If unsure, say N.
-
-config SERIAL_8250_RSA
-       bool "Support RSA serial ports"
-       depends on SERIAL_8250_EXTENDED
-       help
-         ::: To be written :::
-
 #
 # Multi-port serial cards
 #
@@ -199,7 +173,6 @@ config SERIAL_8250_ACCENT
          To compile this driver as a module, choose M here: the module
          will be called 8250_accent.
 
-
 config SERIAL_8250_BOCA
        tristate "Support Boca cards"
        depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
@@ -230,6 +203,32 @@ config SERIAL_8250_HUB6
          To compile this driver as a module, choose M here: the module
          will be called 8250_hub6.
 
+config SERIAL_8250_SHARE_IRQ
+       bool "Support for sharing serial interrupts"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Some serial boards have hardware support which allows multiple dumb
+         serial ports on the same board to share a single IRQ. To enable
+         support for this in the serial driver, say Y here.
+
+config SERIAL_8250_DETECT_IRQ
+       bool "Autodetect IRQ on standard ports (unsafe)"
+       depends on SERIAL_8250_EXTENDED
+       help
+         Say Y here if you want the kernel to try to guess which IRQ
+         to use for your serial port.
+
+         This is considered unsafe; it is far better to configure the IRQ in
+         a boot script using the setserial command.
+
+         If unsure, say N.
+
+config SERIAL_8250_RSA
+       bool "Support RSA serial ports"
+       depends on SERIAL_8250_EXTENDED
+       help
+         ::: To be written :::
+
 config SERIAL_8250_MCA
        tristate "Support 8250-type ports on MCA buses"
        depends on SERIAL_8250 != n && MCA
index 9031b57f12ddd754e93db42015d69e47ffabade4..c53b69610a51005c0b845eb9a63c00e900a311e7 100644 (file)
@@ -319,6 +319,28 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 
        sci_out(port, SCFCR, fcr_val);
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+       unsigned int fcr_val = 0;
+
+       if (cflag & CRTSCTS) {
+               fcr_val |= SCFCR_MCE;
+
+               ctrl_outw(0x0000, PORT_PSCR);
+       } else {
+               unsigned short data;
+
+               data = ctrl_inw(PORT_PSCR);
+               data &= 0x033f;
+               data |= 0x0400;
+               ctrl_outw(data, PORT_PSCR);
+
+               ctrl_outw(ctrl_inw(SCSPTR0) & 0x17, SCSPTR0);
+       }
+
+       sci_out(port, SCFCR, fcr_val);
+}
 #else
 /* For SH7750 */
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
index e4557cc4f74b546493f1297648233e1c2b2447ee..77f7d6351ab18a285b3a35517d1a3b0162ac87d1 100644 (file)
 # define SCSPTR3 0xffe30010    /* 16 bit SCIF */
 # define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
 # define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
+# define SCSPTR0               SCPDR0
+# define SCIF_ORER             0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
+# define PORT_PSCR             0xA405011E
 #elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
 # define SCSPTR2 0xffe80020 /* 16 bit SCIF */
 # define SCIF_ORER 0x0001   /* overrun error bit */
@@ -495,6 +502,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xfe620000)
                return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7300)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -521,6 +529,13 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
        return 1;
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xffe00000)
+               return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
+       return 1;
+}
 #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 static inline int sci_rxd_in(struct uart_port *port)
 {
@@ -550,6 +565,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xff925000)
                return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -558,6 +574,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xffe10000)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -570,6 +587,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xfffe9800)
                return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
 static inline int sci_rxd_in(struct uart_port *port)
@@ -580,6 +598,7 @@ static inline int sci_rxd_in(struct uart_port *port)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
        if (port->mapbase == 0xf8420000)
                return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+       return 1;
 }
 #endif
 
index 494d9b85648879ba42de6a1c45b03f294fa589a6..6ed3f1da9296f594edd83bd65c7fc062a9f07f56 100644 (file)
@@ -49,6 +49,14 @@ MODULE_LICENSE("GPL");
 #define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
 #define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
 
+/* for testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables */
+#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_EBCEI | SSCR1_SCFR \
+                               | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
+                               | SSCR1_RWOT | SSCR1_TRAIL | SSCR1_PINTE \
+                               | SSCR1_STRF | SSCR1_EFWR |SSCR1_RFT \
+                               | SSCR1_TFT | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+
 #define DEFINE_SSP_REG(reg, off) \
 static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
 static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
@@ -123,8 +131,8 @@ struct driver_data {
        u8 n_bytes;
        u32 dma_width;
        int cs_change;
-       void (*write)(struct driver_data *drv_data);
-       void (*read)(struct driver_data *drv_data);
+       int (*write)(struct driver_data *drv_data);
+       int (*read)(struct driver_data *drv_data);
        irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
        void (*cs_control)(u32 command);
 };
@@ -132,7 +140,6 @@ struct driver_data {
 struct chip_data {
        u32 cr0;
        u32 cr1;
-       u32 to;
        u32 psp;
        u32 timeout;
        u8 n_bytes;
@@ -143,8 +150,8 @@ struct chip_data {
        u8 enable_dma;
        u8 bits_per_word;
        u32 speed_hz;
-       void (*write)(struct driver_data *drv_data);
-       void (*read)(struct driver_data *drv_data);
+       int (*write)(struct driver_data *drv_data);
+       int (*read)(struct driver_data *drv_data);
        void (*cs_control)(u32 command);
 };
 
@@ -166,114 +173,118 @@ static int flush(struct driver_data *drv_data)
        return limit;
 }
 
-static void restore_state(struct driver_data *drv_data)
-{
-       void *reg = drv_data->ioaddr;
-
-       /* Clear status and disable clock */
-       write_SSSR(drv_data->clear_sr, reg);
-       write_SSCR0(drv_data->cur_chip->cr0 & ~SSCR0_SSE, reg);
-
-       /* Load the registers */
-       write_SSCR1(drv_data->cur_chip->cr1, reg);
-       write_SSCR0(drv_data->cur_chip->cr0, reg);
-       if (drv_data->ssp_type != PXA25x_SSP) {
-               write_SSTO(0, reg);
-               write_SSPSP(drv_data->cur_chip->psp, reg);
-       }
-}
-
 static void null_cs_control(u32 command)
 {
 }
 
-static void null_writer(struct driver_data *drv_data)
+static int null_writer(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
        u8 n_bytes = drv_data->n_bytes;
 
-       while ((read_SSSR(reg) & SSSR_TNF)
-                       && (drv_data->tx < drv_data->tx_end)) {
-               write_SSDR(0, reg);
-               drv_data->tx += n_bytes;
-       }
+       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+               || (drv_data->tx == drv_data->tx_end))
+               return 0;
+
+       write_SSDR(0, reg);
+       drv_data->tx += n_bytes;
+
+       return 1;
 }
 
-static void null_reader(struct driver_data *drv_data)
+static int null_reader(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
        u8 n_bytes = drv_data->n_bytes;
 
        while ((read_SSSR(reg) & SSSR_RNE)
-                       && (drv_data->rx < drv_data->rx_end)) {
+               && (drv_data->rx < drv_data->rx_end)) {
                read_SSDR(reg);
                drv_data->rx += n_bytes;
        }
+
+       return drv_data->rx == drv_data->rx_end;
 }
 
-static void u8_writer(struct driver_data *drv_data)
+static int u8_writer(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
-       while ((read_SSSR(reg) & SSSR_TNF)
-                       && (drv_data->tx < drv_data->tx_end)) {
-               write_SSDR(*(u8 *)(drv_data->tx), reg);
-               ++drv_data->tx;
-       }
+       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+               || (drv_data->tx == drv_data->tx_end))
+               return 0;
+
+       write_SSDR(*(u8 *)(drv_data->tx), reg);
+       ++drv_data->tx;
+
+       return 1;
 }
 
-static void u8_reader(struct driver_data *drv_data)
+static int u8_reader(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
        while ((read_SSSR(reg) & SSSR_RNE)
-                       && (drv_data->rx < drv_data->rx_end)) {
+               && (drv_data->rx < drv_data->rx_end)) {
                *(u8 *)(drv_data->rx) = read_SSDR(reg);
                ++drv_data->rx;
        }
+
+       return drv_data->rx == drv_data->rx_end;
 }
 
-static void u16_writer(struct driver_data *drv_data)
+static int u16_writer(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
-       while ((read_SSSR(reg) & SSSR_TNF)
-                       && (drv_data->tx < drv_data->tx_end)) {
-               write_SSDR(*(u16 *)(drv_data->tx), reg);
-               drv_data->tx += 2;
-       }
+       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+               || (drv_data->tx == drv_data->tx_end))
+               return 0;
+
+       write_SSDR(*(u16 *)(drv_data->tx), reg);
+       drv_data->tx += 2;
+
+       return 1;
 }
 
-static void u16_reader(struct driver_data *drv_data)
+static int u16_reader(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
        while ((read_SSSR(reg) & SSSR_RNE)
-                       && (drv_data->rx < drv_data->rx_end)) {
+               && (drv_data->rx < drv_data->rx_end)) {
                *(u16 *)(drv_data->rx) = read_SSDR(reg);
                drv_data->rx += 2;
        }
+
+       return drv_data->rx == drv_data->rx_end;
 }
-static void u32_writer(struct driver_data *drv_data)
+
+static int u32_writer(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
-       while ((read_SSSR(reg) & SSSR_TNF)
-                       && (drv_data->tx < drv_data->tx_end)) {
-               write_SSDR(*(u32 *)(drv_data->tx), reg);
-               drv_data->tx += 4;
-       }
+       if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
+               || (drv_data->tx == drv_data->tx_end))
+               return 0;
+
+       write_SSDR(*(u32 *)(drv_data->tx), reg);
+       drv_data->tx += 4;
+
+       return 1;
 }
 
-static void u32_reader(struct driver_data *drv_data)
+static int u32_reader(struct driver_data *drv_data)
 {
        void *reg = drv_data->ioaddr;
 
        while ((read_SSSR(reg) & SSSR_RNE)
-                       && (drv_data->rx < drv_data->rx_end)) {
+               && (drv_data->rx < drv_data->rx_end)) {
                *(u32 *)(drv_data->rx) = read_SSDR(reg);
                drv_data->rx += 4;
        }
+
+       return drv_data->rx == drv_data->rx_end;
 }
 
 static void *next_transfer(struct driver_data *drv_data)
@@ -409,166 +420,134 @@ static int wait_dma_channel_stop(int channel)
        return limit;
 }
 
-static void dma_handler(int channel, void *data)
+void dma_error_stop(struct driver_data *drv_data, const char *msg)
 {
-       struct driver_data *drv_data = data;
-       struct spi_message *msg = drv_data->cur_msg;
        void *reg = drv_data->ioaddr;
-       u32 irq_status = DCSR(channel) & DMA_INT_MASK;
-       u32 trailing_sssr = 0;
 
-       if (irq_status & DCSR_BUSERR) {
+       /* Stop and reset */
+       DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+       DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+       write_SSSR(drv_data->clear_sr, reg);
+       write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+       if (drv_data->ssp_type != PXA25x_SSP)
+               write_SSTO(0, reg);
+       flush(drv_data);
+       write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 
-               /* Disable interrupts, clear status and reset DMA */
-               write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-               write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-               if (drv_data->ssp_type != PXA25x_SSP)
-                       write_SSTO(0, reg);
-               write_SSSR(drv_data->clear_sr, reg);
-               DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-               DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+       unmap_dma_buffers(drv_data);
 
-               if (flush(drv_data) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                                       "dma_handler: flush fail\n");
+       dev_err(&drv_data->pdev->dev, "%s\n", msg);
 
-               unmap_dma_buffers(drv_data);
+       drv_data->cur_msg->state = ERROR_STATE;
+       tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void dma_transfer_complete(struct driver_data *drv_data)
+{
+       void *reg = drv_data->ioaddr;
+       struct spi_message *msg = drv_data->cur_msg;
+
+       /* Clear and disable interrupts on SSP and DMA channels*/
+       write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+       write_SSSR(drv_data->clear_sr, reg);
+       DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+       DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+       if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+               dev_err(&drv_data->pdev->dev,
+                       "dma_handler: dma rx channel stop failed\n");
+
+       if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+               dev_err(&drv_data->pdev->dev,
+                       "dma_transfer: ssp rx stall failed\n");
+
+       unmap_dma_buffers(drv_data);
+
+       /* update the buffer pointer for the amount completed in dma */
+       drv_data->rx += drv_data->len -
+                       (DCMD(drv_data->rx_channel) & DCMD_LENGTH);
+
+       /* read trailing data from fifo, it does not matter how many
+        * bytes are in the fifo just read until buffer is full
+        * or fifo is empty, which ever occurs first */
+       drv_data->read(drv_data);
+
+       /* return count of what was actually read */
+       msg->actual_length += drv_data->len -
+                               (drv_data->rx_end - drv_data->rx);
+
+       /* Release chip select if requested, transfer delays are
+        * handled in pump_transfers */
+       if (drv_data->cs_change)
+               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+
+       /* Move to next transfer */
+       msg->state = next_transfer(drv_data);
+
+       /* Schedule transfer tasklet */
+       tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void dma_handler(int channel, void *data)
+{
+       struct driver_data *drv_data = data;
+       u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+       if (irq_status & DCSR_BUSERR) {
 
                if (channel == drv_data->tx_channel)
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_handler: bad bus address on "
-                               "tx channel %d, source %x target = %x\n",
-                               channel, DSADR(channel), DTADR(channel));
+                       dma_error_stop(drv_data,
+                                       "dma_handler: "
+                                       "bad bus address on tx channel");
                else
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_handler: bad bus address on "
-                               "rx channel %d, source %x target = %x\n",
-                               channel, DSADR(channel), DTADR(channel));
-
-               msg->state = ERROR_STATE;
-               tasklet_schedule(&drv_data->pump_transfers);
+                       dma_error_stop(drv_data,
+                                       "dma_handler: "
+                                       "bad bus address on rx channel");
+               return;
        }
 
        /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
-       if ((drv_data->ssp_type == PXA25x_SSP)
-               && (channel == drv_data->tx_channel)
-               && (irq_status & DCSR_ENDINTR)) {
+       if ((channel == drv_data->tx_channel)
+               && (irq_status & DCSR_ENDINTR)
+               && (drv_data->ssp_type == PXA25x_SSP)) {
 
                /* Wait for rx to stall */
                if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
                        dev_err(&drv_data->pdev->dev,
                                "dma_handler: ssp rx stall failed\n");
 
-               /* Clear and disable interrupts on SSP and DMA channels*/
-               write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-               write_SSSR(drv_data->clear_sr, reg);
-               DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-               DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-               if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_handler: dma rx channel stop failed\n");
-
-               unmap_dma_buffers(drv_data);
-
-               /* Read trailing bytes */
-               /* Calculate number of trailing bytes, read them */
-               trailing_sssr = read_SSSR(reg);
-               if ((trailing_sssr & 0xf008) != 0xf000) {
-                       drv_data->rx = drv_data->rx_end -
-                                       (((trailing_sssr >> 12) & 0x0f) + 1);
-                       drv_data->read(drv_data);
-               }
-               msg->actual_length += drv_data->len;
-
-               /* Release chip select if requested, transfer delays are
-                * handled in pump_transfers */
-               if (drv_data->cs_change)
-                       drv_data->cs_control(PXA2XX_CS_DEASSERT);
-
-               /* Move to next transfer */
-               msg->state = next_transfer(drv_data);
-
-               /* Schedule transfer tasklet */
-               tasklet_schedule(&drv_data->pump_transfers);
+               /* finish this transfer, start the next */
+               dma_transfer_complete(drv_data);
        }
 }
 
 static irqreturn_t dma_transfer(struct driver_data *drv_data)
 {
        u32 irq_status;
-       u32 trailing_sssr = 0;
-       struct spi_message *msg = drv_data->cur_msg;
        void *reg = drv_data->ioaddr;
 
        irq_status = read_SSSR(reg) & drv_data->mask_sr;
        if (irq_status & SSSR_ROR) {
-               /* Clear and disable interrupts on SSP and DMA channels*/
-               write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-               write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-               if (drv_data->ssp_type != PXA25x_SSP)
-                       write_SSTO(0, reg);
-               write_SSSR(drv_data->clear_sr, reg);
-               DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-               DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-               unmap_dma_buffers(drv_data);
-
-               if (flush(drv_data) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                                       "dma_transfer: flush fail\n");
-
-               dev_warn(&drv_data->pdev->dev, "dma_transfer: fifo overun\n");
-
-               drv_data->cur_msg->state = ERROR_STATE;
-               tasklet_schedule(&drv_data->pump_transfers);
-
+               dma_error_stop(drv_data, "dma_transfer: fifo overrun");
                return IRQ_HANDLED;
        }
 
        /* Check for false positive timeout */
-       if ((irq_status & SSSR_TINT) && DCSR(drv_data->tx_channel) & DCSR_RUN) {
+       if ((irq_status & SSSR_TINT)
+               && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
                write_SSSR(SSSR_TINT, reg);
                return IRQ_HANDLED;
        }
 
        if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
 
-               /* Clear and disable interrupts on SSP and DMA channels*/
-               write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+               /* Clear and disable timeout interrupt, do the rest in
+                * dma_transfer_complete */
                if (drv_data->ssp_type != PXA25x_SSP)
                        write_SSTO(0, reg);
-               write_SSSR(drv_data->clear_sr, reg);
-               DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-               DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
 
-               if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_transfer: dma rx channel stop failed\n");
-
-               if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_transfer: ssp rx stall failed\n");
-
-               unmap_dma_buffers(drv_data);
-
-               /* Calculate number of trailing bytes, read them */
-               trailing_sssr = read_SSSR(reg);
-               if ((trailing_sssr & 0xf008) != 0xf000) {
-                       drv_data->rx = drv_data->rx_end -
-                                       (((trailing_sssr >> 12) & 0x0f) + 1);
-                       drv_data->read(drv_data);
-               }
-               msg->actual_length += drv_data->len;
-
-               /* Release chip select if requested, transfer delays are
-                * handled in pump_transfers */
-               if (drv_data->cs_change)
-                       drv_data->cs_control(PXA2XX_CS_DEASSERT);
-
-               /* Move to next transfer */
-               msg->state = next_transfer(drv_data);
-
-               /* Schedule transfer tasklet */
-               tasklet_schedule(&drv_data->pump_transfers);
+               /* finish this transfer, start the next */
+               dma_transfer_complete(drv_data);
 
                return IRQ_HANDLED;
        }
@@ -577,89 +556,103 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
        return IRQ_NONE;
 }
 
-static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+static void int_error_stop(struct driver_data *drv_data, const char* msg)
 {
-       struct spi_message *msg = drv_data->cur_msg;
        void *reg = drv_data->ioaddr;
-       unsigned long limit = loops_per_jiffy << 1;
-       u32 irq_status;
-       u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
-                       drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
-
-       while ((irq_status = read_SSSR(reg) & irq_mask)) {
-
-               if (irq_status & SSSR_ROR) {
 
-                       /* Clear and disable interrupts */
-                       write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-                       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-                       if (drv_data->ssp_type != PXA25x_SSP)
-                               write_SSTO(0, reg);
-                       write_SSSR(drv_data->clear_sr, reg);
+       /* Stop and reset SSP */
+       write_SSSR(drv_data->clear_sr, reg);
+       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+       if (drv_data->ssp_type != PXA25x_SSP)
+               write_SSTO(0, reg);
+       flush(drv_data);
+       write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 
-                       if (flush(drv_data) == 0)
-                               dev_err(&drv_data->pdev->dev,
-                                       "interrupt_transfer: flush fail\n");
+       dev_err(&drv_data->pdev->dev, "%s\n", msg);
 
-                       /* Stop the SSP */
+       drv_data->cur_msg->state = ERROR_STATE;
+       tasklet_schedule(&drv_data->pump_transfers);
+}
 
-                       dev_warn(&drv_data->pdev->dev,
-                                       "interrupt_transfer: fifo overun\n");
+static void int_transfer_complete(struct driver_data *drv_data)
+{
+       void *reg = drv_data->ioaddr;
 
-                       msg->state = ERROR_STATE;
-                       tasklet_schedule(&drv_data->pump_transfers);
+       /* Stop SSP */
+       write_SSSR(drv_data->clear_sr, reg);
+       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+       if (drv_data->ssp_type != PXA25x_SSP)
+               write_SSTO(0, reg);
 
-                       return IRQ_HANDLED;
-               }
+       /* Update total byte transfered return count actual bytes read */
+       drv_data->cur_msg->actual_length += drv_data->len -
+                               (drv_data->rx_end - drv_data->rx);
 
-               /* Look for false positive timeout */
-               if ((irq_status & SSSR_TINT)
-                               && (drv_data->rx < drv_data->rx_end))
-                       write_SSSR(SSSR_TINT, reg);
+       /* Release chip select if requested, transfer delays are
+        * handled in pump_transfers */
+       if (drv_data->cs_change)
+               drv_data->cs_control(PXA2XX_CS_DEASSERT);
 
-               /* Pump data */
-               drv_data->read(drv_data);
-               drv_data->write(drv_data);
+       /* Move to next transfer */
+       drv_data->cur_msg->state = next_transfer(drv_data);
 
-               if (drv_data->tx == drv_data->tx_end) {
-                       /* Disable tx interrupt */
-                       write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
-                       irq_mask = drv_data->mask_sr & ~SSSR_TFS;
+       /* Schedule transfer tasklet */
+       tasklet_schedule(&drv_data->pump_transfers);
+}
 
-                       /* PXA25x_SSP has no timeout, read trailing bytes */
-                       if (drv_data->ssp_type == PXA25x_SSP) {
-                               while ((read_SSSR(reg) & SSSR_BSY) && limit--)
-                                       drv_data->read(drv_data);
+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+{
+       void *reg = drv_data->ioaddr;
 
-                               if (limit == 0)
-                                       dev_err(&drv_data->pdev->dev,
-                                               "interrupt_transfer: "
-                                               "trailing byte read failed\n");
-                       }
-               }
+       u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
+                       drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
 
-               if ((irq_status & SSSR_TINT)
-                               || (drv_data->rx == drv_data->rx_end)) {
+       u32 irq_status = read_SSSR(reg) & irq_mask;
 
-                       /* Clear timeout */
-                       write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-                       if (drv_data->ssp_type != PXA25x_SSP)
-                               write_SSTO(0, reg);
-                       write_SSSR(drv_data->clear_sr, reg);
+       if (irq_status & SSSR_ROR) {
+               int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+               return IRQ_HANDLED;
+       }
 
-                       /* Update total byte transfered */
-                       msg->actual_length += drv_data->len;
+       if (irq_status & SSSR_TINT) {
+               write_SSSR(SSSR_TINT, reg);
+               if (drv_data->read(drv_data)) {
+                       int_transfer_complete(drv_data);
+                       return IRQ_HANDLED;
+               }
+       }
 
-                       /* Release chip select if requested, transfer delays are
-                        * handled in pump_transfers */
-                       if (drv_data->cs_change)
-                               drv_data->cs_control(PXA2XX_CS_DEASSERT);
+       /* Drain rx fifo, Fill tx fifo and prevent overruns */
+       do {
+               if (drv_data->read(drv_data)) {
+                       int_transfer_complete(drv_data);
+                       return IRQ_HANDLED;
+               }
+       } while (drv_data->write(drv_data));
 
-                       /* Move to next transfer */
-                       msg->state = next_transfer(drv_data);
+       if (drv_data->read(drv_data)) {
+               int_transfer_complete(drv_data);
+               return IRQ_HANDLED;
+       }
 
-                       /* Schedule transfer tasklet */
-                       tasklet_schedule(&drv_data->pump_transfers);
+       if (drv_data->tx == drv_data->tx_end) {
+               write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
+               /* PXA25x_SSP has no timeout, read trailing bytes */
+               if (drv_data->ssp_type == PXA25x_SSP) {
+                       if (!wait_ssp_rx_stall(reg))
+                       {
+                               int_error_stop(drv_data, "interrupt_transfer: "
+                                               "rx stall failed");
+                               return IRQ_HANDLED;
+                       }
+                       if (!drv_data->read(drv_data))
+                       {
+                               int_error_stop(drv_data,
+                                               "interrupt_transfer: "
+                                               "trailing byte read failed");
+                               return IRQ_HANDLED;
+                       }
+                       int_transfer_complete(drv_data);
                }
        }
 
@@ -681,7 +674,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
                write_SSSR(drv_data->clear_sr, reg);
 
                dev_err(&drv_data->pdev->dev, "bad message state "
-                               "in interrupt handler");
+                       "in interrupt handler\n");
 
                /* Never fail */
                return IRQ_HANDLED;
@@ -690,6 +683,102 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
        return drv_data->transfer_handler(drv_data);
 }
 
+int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
+                               u8 bits_per_word, u32 *burst_code,
+                               u32 *threshold)
+{
+       struct pxa2xx_spi_chip *chip_info =
+                       (struct pxa2xx_spi_chip *)spi->controller_data;
+       int bytes_per_word;
+       int burst_bytes;
+       int thresh_words;
+       int req_burst_size;
+       int retval = 0;
+
+       /* Set the threshold (in registers) to equal the same amount of data
+        * as represented by burst size (in bytes).  The computation below
+        * is (burst_size rounded up to nearest 8 byte, word or long word)
+        * divided by (bytes/register); the tx threshold is the inverse of
+        * the rx, so that there will always be enough data in the rx fifo
+        * to satisfy a burst, and there will always be enough space in the
+        * tx fifo to accept a burst (a tx burst will overwrite the fifo if
+        * there is not enough space), there must always remain enough empty
+        * space in the rx fifo for any data loaded to the tx fifo.
+        * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
+        * will be 8, or half the fifo;
+        * The threshold can only be set to 2, 4 or 8, but not 16, because
+        * to burst 16 to the tx fifo, the fifo would have to be empty;
+        * however, the minimum fifo trigger level is 1, and the tx will
+        * request service when the fifo is at this level, with only 15 spaces.
+        */
+
+       /* find bytes/word */
+       if (bits_per_word <= 8)
+               bytes_per_word = 1;
+       else if (bits_per_word <= 16)
+               bytes_per_word = 2;
+       else
+               bytes_per_word = 4;
+
+       /* use struct pxa2xx_spi_chip->dma_burst_size if available */
+       if (chip_info)
+               req_burst_size = chip_info->dma_burst_size;
+       else {
+               switch (chip->dma_burst_size) {
+               default:
+                       /* if the default burst size is not set,
+                        * do it now */
+                       chip->dma_burst_size = DCMD_BURST8;
+               case DCMD_BURST8:
+                       req_burst_size = 8;
+                       break;
+               case DCMD_BURST16:
+                       req_burst_size = 16;
+                       break;
+               case DCMD_BURST32:
+                       req_burst_size = 32;
+                       break;
+               }
+       }
+       if (req_burst_size <= 8) {
+               *burst_code = DCMD_BURST8;
+               burst_bytes = 8;
+       } else if (req_burst_size <= 16) {
+               if (bytes_per_word == 1) {
+                       /* don't burst more than 1/2 the fifo */
+                       *burst_code = DCMD_BURST8;
+                       burst_bytes = 8;
+                       retval = 1;
+               } else {
+                       *burst_code = DCMD_BURST16;
+                       burst_bytes = 16;
+               }
+       } else {
+               if (bytes_per_word == 1) {
+                       /* don't burst more than 1/2 the fifo */
+                       *burst_code = DCMD_BURST8;
+                       burst_bytes = 8;
+                       retval = 1;
+               } else if (bytes_per_word == 2) {
+                       /* don't burst more than 1/2 the fifo */
+                       *burst_code = DCMD_BURST16;
+                       burst_bytes = 16;
+                       retval = 1;
+               } else {
+                       *burst_code = DCMD_BURST32;
+                       burst_bytes = 32;
+               }
+       }
+
+       thresh_words = burst_bytes / bytes_per_word;
+
+       /* thresh_words will be between 2 and 8 */
+       *threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
+                       | (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
+
+       return retval;
+}
+
 static void pump_transfers(unsigned long data)
 {
        struct driver_data *drv_data = (struct driver_data *)data;
@@ -702,6 +791,9 @@ static void pump_transfers(unsigned long data)
        u8 bits = 0;
        u32 speed = 0;
        u32 cr0;
+       u32 cr1;
+       u32 dma_thresh = drv_data->cur_chip->dma_threshold;
+       u32 dma_burst = drv_data->cur_chip->dma_burst_size;
 
        /* Get current state information */
        message = drv_data->cur_msg;
@@ -731,6 +823,16 @@ static void pump_transfers(unsigned long data)
                        udelay(previous->delay_usecs);
        }
 
+       /* Check transfer length */
+       if (transfer->len > 8191)
+       {
+               dev_warn(&drv_data->pdev->dev, "pump_transfers: transfer "
+                               "length greater than 8191\n");
+               message->status = -EINVAL;
+               giveback(drv_data);
+               return;
+       }
+
        /* Setup the transfer state based on the type of transfer */
        if (flush(drv_data) == 0) {
                dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
@@ -747,17 +849,15 @@ static void pump_transfers(unsigned long data)
        drv_data->rx_end = drv_data->rx + transfer->len;
        drv_data->rx_dma = transfer->rx_dma;
        drv_data->tx_dma = transfer->tx_dma;
-       drv_data->len = transfer->len;
+       drv_data->len = transfer->len & DCMD_LENGTH;
        drv_data->write = drv_data->tx ? chip->write : null_writer;
        drv_data->read = drv_data->rx ? chip->read : null_reader;
        drv_data->cs_change = transfer->cs_change;
 
        /* Change speed and bit per word on a per transfer */
+       cr0 = chip->cr0;
        if (transfer->speed_hz || transfer->bits_per_word) {
 
-               /* Disable clock */
-               write_SSCR0(chip->cr0 & ~SSCR0_SSE, reg);
-               cr0 = chip->cr0;
                bits = chip->bits_per_word;
                speed = chip->speed_hz;
 
@@ -796,15 +896,24 @@ static void pump_transfers(unsigned long data)
                        drv_data->write = drv_data->write != null_writer ?
                                                u32_writer : null_writer;
                }
+               /* if bits/word is changed in dma mode, then must check the
+                * thresholds and burst also */
+               if (chip->enable_dma) {
+                       if (set_dma_burst_and_threshold(chip, message->spi,
+                                                       bits, &dma_burst,
+                                                       &dma_thresh))
+                               if (printk_ratelimit())
+                                       dev_warn(&message->spi->dev,
+                                               "pump_transfer: "
+                                               "DMA burst size reduced to "
+                                               "match bits_per_word\n");
+               }
 
                cr0 = clk_div
                        | SSCR0_Motorola
                        | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
                        | SSCR0_SSE
                        | (bits > 16 ? SSCR0_EDSS : 0);
-
-               /* Start it back up */
-               write_SSCR0(cr0, reg);
        }
 
        message->state = RUNNING_STATE;
@@ -823,13 +932,13 @@ static void pump_transfers(unsigned long data)
                        /* No target address increment */
                        DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
                                                        | drv_data->dma_width
-                                                       | chip->dma_burst_size
+                                                       | dma_burst
                                                        | drv_data->len;
                else
                        DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
                                                        | DCMD_FLOWSRC
                                                        | drv_data->dma_width
-                                                       | chip->dma_burst_size
+                                                       | dma_burst
                                                        | drv_data->len;
 
                /* Setup tx DMA Channel */
@@ -840,13 +949,13 @@ static void pump_transfers(unsigned long data)
                        /* No source address increment */
                        DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
                                                        | drv_data->dma_width
-                                                       | chip->dma_burst_size
+                                                       | dma_burst
                                                        | drv_data->len;
                else
                        DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
                                                        | DCMD_FLOWTRG
                                                        | drv_data->dma_width
-                                                       | chip->dma_burst_size
+                                                       | dma_burst
                                                        | drv_data->len;
 
                /* Enable dma end irqs on SSP to detect end of transfer */
@@ -856,16 +965,11 @@ static void pump_transfers(unsigned long data)
                /* Fix me, need to handle cs polarity */
                drv_data->cs_control(PXA2XX_CS_ASSERT);
 
-               /* Go baby, go */
+               /* Clear status and start DMA engine */
+               cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
                write_SSSR(drv_data->clear_sr, reg);
                DCSR(drv_data->rx_channel) |= DCSR_RUN;
                DCSR(drv_data->tx_channel) |= DCSR_RUN;
-               if (drv_data->ssp_type != PXA25x_SSP)
-                       write_SSTO(chip->timeout, reg);
-               write_SSCR1(chip->cr1
-                               | chip->dma_threshold
-                               | drv_data->dma_cr1,
-                               reg);
        } else {
                /* Ensure we have the correct interrupt handler */
                drv_data->transfer_handler = interrupt_transfer;
@@ -873,14 +977,25 @@ static void pump_transfers(unsigned long data)
                /* Fix me, need to handle cs polarity */
                drv_data->cs_control(PXA2XX_CS_ASSERT);
 
-               /* Go baby, go */
+               /* Clear status  */
+               cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
                write_SSSR(drv_data->clear_sr, reg);
+       }
+
+       /* see if we need to reload the config registers */
+       if ((read_SSCR0(reg) != cr0)
+               || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
+                       (cr1 & SSCR1_CHANGE_MASK)) {
+
+               write_SSCR0(cr0 & ~SSCR0_SSE, reg);
                if (drv_data->ssp_type != PXA25x_SSP)
                        write_SSTO(chip->timeout, reg);
-               write_SSCR1(chip->cr1
-                               | chip->threshold
-                               | drv_data->int_cr1,
-                               reg);
+               write_SSCR1(cr1, reg);
+               write_SSCR0(cr0, reg);
+       } else {
+               if (drv_data->ssp_type != PXA25x_SSP)
+                       write_SSTO(chip->timeout, reg);
+               write_SSCR1(cr1, reg);
        }
 }
 
@@ -915,9 +1030,9 @@ static void pump_messages(struct work_struct *work)
                                                struct spi_transfer,
                                                transfer_list);
 
-       /* Setup the SSP using the per chip configuration */
+       /* prepare to setup the SSP, in pump_transfers, using the per
+        * chip configuration */
        drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-       restore_state(drv_data);
 
        /* Mark as busy and launch transfers */
        tasklet_schedule(&drv_data->pump_transfers);
@@ -963,63 +1078,77 @@ static int setup(struct spi_device *spi)
                spi->bits_per_word = 8;
 
        if (drv_data->ssp_type != PXA25x_SSP
-                       && (spi->bits_per_word < 4 || spi->bits_per_word > 32))
+               && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
+               dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+                               "b/w not 4-32 for type non-PXA25x_SSP\n",
+                               drv_data->ssp_type, spi->bits_per_word);
                return -EINVAL;
-       else if (spi->bits_per_word < 4 || spi->bits_per_word > 16)
+       }
+       else if (drv_data->ssp_type == PXA25x_SSP
+                       && (spi->bits_per_word < 4
+                               || spi->bits_per_word > 16)) {
+               dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+                               "b/w not 4-16 for type PXA25x_SSP\n",
+                               drv_data->ssp_type, spi->bits_per_word);
                return -EINVAL;
+       }
 
-       /* Only alloc (or use chip_info) on first setup */
+       /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
-       if (chip == NULL) {
+       if (!chip) {
                chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
-               if (!chip)
+               if (!chip) {
+                       dev_err(&spi->dev,
+                               "failed setup: can't allocate chip data\n");
                        return -ENOMEM;
+               }
 
                chip->cs_control = null_cs_control;
                chip->enable_dma = 0;
-               chip->timeout = SSP_TIMEOUT(1000);
+               chip->timeout = 1000;
                chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
                chip->dma_burst_size = drv_data->master_info->enable_dma ?
                                        DCMD_BURST8 : 0;
-
-               chip_info = spi->controller_data;
        }
 
+       /* protocol drivers may change the chip settings, so...
+        * if chip_info exists, use it */
+       chip_info = spi->controller_data;
+
        /* chip_info isn't always needed */
+       chip->cr1 = 0;
        if (chip_info) {
                if (chip_info->cs_control)
                        chip->cs_control = chip_info->cs_control;
 
-               chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs);
+               chip->timeout = chip_info->timeout;
 
-               chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold)
-                                       | SSCR1_TxTresh(chip_info->tx_threshold);
+               chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
+                                                               SSCR1_RFT) |
+                               (SSCR1_TxTresh(chip_info->tx_threshold) &
+                                                               SSCR1_TFT);
 
                chip->enable_dma = chip_info->dma_burst_size != 0
                                        && drv_data->master_info->enable_dma;
                chip->dma_threshold = 0;
 
-               if (chip->enable_dma) {
-                       if (chip_info->dma_burst_size <= 8) {
-                               chip->dma_threshold = SSCR1_RxTresh(8)
-                                                       | SSCR1_TxTresh(8);
-                               chip->dma_burst_size = DCMD_BURST8;
-                       } else if (chip_info->dma_burst_size <= 16) {
-                               chip->dma_threshold = SSCR1_RxTresh(16)
-                                                       | SSCR1_TxTresh(16);
-                               chip->dma_burst_size = DCMD_BURST16;
-                       } else {
-                               chip->dma_threshold = SSCR1_RxTresh(32)
-                                                       | SSCR1_TxTresh(32);
-                               chip->dma_burst_size = DCMD_BURST32;
-                       }
-               }
-
-
                if (chip_info->enable_loopback)
                        chip->cr1 = SSCR1_LBM;
        }
 
+       /* set dma burst and threshold outside of chip_info path so that if
+        * chip_info goes away after setting chip->enable_dma, the
+        * burst and threshold can still respond to changes in bits_per_word */
+       if (chip->enable_dma) {
+               /* set up legal burst and threshold for dma */
+               if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
+                                               &chip->dma_burst_size,
+                                               &chip->dma_threshold)) {
+                       dev_warn(&spi->dev, "in setup: DMA burst size reduced "
+                                       "to match bits_per_word\n");
+               }
+       }
+
        if (drv_data->ioaddr == SSP1_VIRT)
                clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
        else if (drv_data->ioaddr == SSP2_VIRT)
@@ -1027,7 +1156,11 @@ static int setup(struct spi_device *spi)
        else if (drv_data->ioaddr == SSP3_VIRT)
                clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
        else
+       {
+               dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
+                       drv_data->ioaddr);
                return -ENODEV;
+       }
        chip->speed_hz = spi->max_speed_hz;
 
        chip->cr0 = clk_div
@@ -1071,7 +1204,6 @@ static int setup(struct spi_device *spi)
                chip->write = u32_writer;
        } else {
                dev_err(&spi->dev, "invalid wordsize\n");
-               kfree(chip);
                return -ENODEV;
        }
        chip->bits_per_word = spi->bits_per_word;
@@ -1162,6 +1294,12 @@ static int destroy_queue(struct driver_data *drv_data)
        int status;
 
        status = stop_queue(drv_data);
+       /* we are unloading the module or failing to load (only two calls
+        * to this routine), and neither call can handle a return value.
+        * However, destroy_workqueue calls flush_workqueue, and that will
+        * block until all work is done.  If the reason that stop_queue
+        * timed out is that the work will never finish, then it does no
+        * good to call destroy_workqueue, so return anyway. */
        if (status != 0)
                return status;
 
@@ -1360,7 +1498,16 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
        /* Remove the queue */
        status = destroy_queue(drv_data);
        if (status != 0)
-               return status;
+               /* the kernel does not check the return status of this
+                * this routine (mod->exit, within the kernel).  Therefore
+                * nothing is gained by returning from here, the module is
+                * going away regardless, and we should not leave any more
+                * resources allocated than necessary.  We cannot free the
+                * message memory in drv_data->queue, but we can release the
+                * resources below.  I think the kernel should honor -EBUSY
+                * returns but... */
+               dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
+                       "complete, message memory not freed\n");
 
        /* Disable the SSP at the peripheral and SOC level */
        write_SSCR0(0, drv_data->ioaddr);
index ab1daecfeac6e1b3c9513094cfe0f3756197add1..4e83f01e894efe30b9cca2da83b6ff35b007e61b 100644 (file)
@@ -1615,6 +1615,16 @@ config FB_PNX4008_DUM_RGB
        ---help---
          Say Y here to enable support for PNX4008 RGB Framebuffer
 
+config FB_IBM_GXT4500
+       tristate "Framebuffer support for IBM GXT4500P adaptor"
+       depends on PPC
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Say Y here to enable support for the IBM GXT4500P display
+         adaptor, found on some IBM System P (pSeries) machines.
+
 config FB_VIRTUAL
        tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
        depends on FB
index a6980e9a2481beb4e15bf06baa87f143b6068726..309a26dd164aede2c8bb57874af4bb60e4cb1c92 100644 (file)
@@ -99,6 +99,7 @@ obj-$(CONFIG_FB_IMX)              += imxfb.o
 obj-$(CONFIG_FB_S3C2410)         += s3c2410fb.o
 obj-$(CONFIG_FB_PNX4008_DUM)     += pnx4008/
 obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx4008/
+obj-$(CONFIG_FB_IBM_GXT4500)     += gxt4500.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c
new file mode 100644 (file)
index 0000000..3adf6ab
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * Frame buffer device for IBM GXT4500P display adaptor
+ *
+ * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+
+#define PCI_DEVICE_ID_IBM_GXT4500P     0x21c
+
+/* GXT4500P registers */
+
+/* Registers in PCI config space */
+#define CFG_ENDIAN0            0x40
+
+/* Misc control/status registers */
+#define STATUS                 0x1000
+#define CTRL_REG0              0x1004
+#define   CR0_HALT_DMA                 0x4
+#define   CR0_RASTER_RESET             0x8
+#define   CR0_GEOM_RESET               0x10
+#define   CR0_MEM_CTRLER_RESET         0x20
+
+/* Framebuffer control registers */
+#define FB_AB_CTRL             0x1100
+#define FB_CD_CTRL             0x1104
+#define FB_WID_CTRL            0x1108
+#define FB_Z_CTRL              0x110c
+#define FB_VGA_CTRL            0x1110
+#define REFRESH_AB_CTRL                0x1114
+#define REFRESH_CD_CTRL                0x1118
+#define FB_OVL_CTRL            0x111c
+#define   FB_CTRL_TYPE                 0x80000000
+#define   FB_CTRL_WIDTH_MASK           0x007f0000
+#define   FB_CTRL_WIDTH_SHIFT          16
+#define   FB_CTRL_START_SEG_MASK       0x00003fff
+
+#define REFRESH_START          0x1098
+#define REFRESH_SIZE           0x109c
+
+/* "Direct" framebuffer access registers */
+#define DFA_FB_A               0x11e0
+#define DFA_FB_B               0x11e4
+#define DFA_FB_C               0x11e8
+#define DFA_FB_D               0x11ec
+#define   DFA_FB_ENABLE                        0x80000000
+#define   DFA_FB_BASE_MASK             0x03f00000
+#define   DFA_FB_STRIDE_1k             0x00000000
+#define   DFA_FB_STRIDE_2k             0x00000010
+#define   DFA_FB_STRIDE_4k             0x00000020
+#define   DFA_PIX_8BIT                 0x00000000
+#define   DFA_PIX_16BIT_565            0x00000001
+#define   DFA_PIX_16BIT_1555           0x00000002
+#define   DFA_PIX_24BIT                        0x00000004
+#define   DFA_PIX_32BIT                        0x00000005
+
+/* maps DFA_PIX_* to pixel size in bytes */
+static const unsigned char pixsize[] = {
+       1, 2, 2, 2, 4, 4
+};
+
+/* Display timing generator registers */
+#define DTG_CONTROL            0x1900
+#define   DTG_CTL_SCREEN_REFRESH       2
+#define   DTG_CTL_ENABLE               1
+#define DTG_HORIZ_EXTENT       0x1904
+#define DTG_HORIZ_DISPLAY      0x1908
+#define DTG_HSYNC_START                0x190c
+#define DTG_HSYNC_END          0x1910
+#define DTG_HSYNC_END_COMP     0x1914
+#define DTG_VERT_EXTENT                0x1918
+#define DTG_VERT_DISPLAY       0x191c
+#define DTG_VSYNC_START                0x1920
+#define DTG_VSYNC_END          0x1924
+#define DTG_VERT_SHORT         0x1928
+
+/* PLL/RAMDAC registers */
+#define DISP_CTL               0x402c
+#define   DISP_CTL_OFF                 2
+#define SYNC_CTL               0x4034
+#define   SYNC_CTL_SYNC_ON_RGB         1
+#define   SYNC_CTL_SYNC_OFF            2
+#define   SYNC_CTL_HSYNC_INV           8
+#define   SYNC_CTL_VSYNC_INV           0x10
+#define   SYNC_CTL_HSYNC_OFF           0x20
+#define   SYNC_CTL_VSYNC_OFF           0x40
+
+#define PLL_M                  0x4040
+#define PLL_N                  0x4044
+#define PLL_POSTDIV            0x4048
+
+/* Hardware cursor */
+#define CURSOR_X               0x4078
+#define CURSOR_Y               0x407c
+#define CURSOR_HOTSPOT         0x4080
+#define CURSOR_MODE            0x4084
+#define   CURSOR_MODE_OFF              0
+#define   CURSOR_MODE_4BPP             1
+#define CURSOR_PIXMAP          0x5000
+#define CURSOR_CMAP            0x7400
+
+/* Window attribute table */
+#define WAT_FMT                        0x4100
+#define   WAT_FMT_24BIT                        0
+#define   WAT_FMT_16BIT_565            1
+#define   WAT_FMT_16BIT_1555           2
+#define   WAT_FMT_32BIT                        3       /* 0 vs. 3 is a guess */
+#define   WAT_FMT_8BIT_332             9
+#define   WAT_FMT_8BIT                 0xa
+#define   WAT_FMT_NO_CMAP              4       /* ORd in to other values */
+#define WAT_CMAP_OFFSET                0x4104          /* 4-bit value gets << 6 */
+#define WAT_CTRL               0x4108
+#define   WAT_CTRL_SEL_B               1       /* select B buffer if 1 */
+#define   WAT_CTRL_NO_INC              2
+#define WAT_GAMMA_CTRL         0x410c
+#define   WAT_GAMMA_DISABLE            1       /* disables gamma cmap */
+#define WAT_OVL_CTRL           0x430c          /* controls overlay */
+
+/* Indexed by DFA_PIX_* values */
+static const unsigned char watfmt[] = {
+       WAT_FMT_8BIT, WAT_FMT_16BIT_565, WAT_FMT_16BIT_1555, 0,
+       WAT_FMT_24BIT, WAT_FMT_32BIT
+};
+
+/* Colormap array; 1k entries of 4 bytes each */
+#define CMAP                   0x6000
+
+#define readreg(par, reg)      readl((par)->regs + (reg))
+#define writereg(par, reg, val)        writel((val), (par)->regs + (reg))
+
+struct gxt4500_par {
+       void __iomem *regs;
+
+       int pixfmt;             /* pixel format, see DFA_PIX_* values */
+
+       /* PLL parameters */
+       int pll_m;              /* ref clock divisor */
+       int pll_n;              /* VCO divisor */
+       int pll_pd1;            /* first post-divisor */
+       int pll_pd2;            /* second post-divisor */
+
+       u32 pseudo_palette[16]; /* used in color blits */
+};
+
+/* mode requested by user */
+static char *mode_option;
+
+/* default mode: 1280x1024 @ 60 Hz, 8 bpp */
+static const struct fb_videomode defaultmode __devinitdata = {
+       .refresh = 60,
+       .xres = 1280,
+       .yres = 1024,
+       .pixclock = 9295,
+       .left_margin = 248,
+       .right_margin = 48,
+       .upper_margin = 38,
+       .lower_margin = 1,
+       .hsync_len = 112,
+       .vsync_len = 3,
+       .vmode = FB_VMODE_NONINTERLACED
+};
+
+/*
+ * The refclk and VCO dividers appear to use a linear feedback shift
+ * register, which gets reloaded when it reaches a terminal value, at
+ * which point the divider output is toggled.  Thus one can obtain
+ * whatever divisor is required by putting the appropriate value into
+ * the reload register.  For a divisor of N, one puts the value from
+ * the LFSR sequence that comes N-1 places before the terminal value
+ * into the reload register.
+ */
+
+static const unsigned char mdivtab[] = {
+/* 1 */                      0x3f, 0x00, 0x20, 0x10, 0x28, 0x14, 0x2a, 0x15, 0x0a,
+/* 10 */       0x25, 0x32, 0x19, 0x0c, 0x26, 0x13, 0x09, 0x04, 0x22, 0x11,
+/* 20 */       0x08, 0x24, 0x12, 0x29, 0x34, 0x1a, 0x2d, 0x36, 0x1b, 0x0d,
+/* 30 */       0x06, 0x23, 0x31, 0x38, 0x1c, 0x2e, 0x17, 0x0b, 0x05, 0x02,
+/* 40 */       0x21, 0x30, 0x18, 0x2c, 0x16, 0x2b, 0x35, 0x3a, 0x1d, 0x0e,
+/* 50 */       0x27, 0x33, 0x39, 0x3c, 0x1e, 0x2f, 0x37, 0x3b, 0x3d, 0x3e,
+/* 60 */       0x1f, 0x0f, 0x07, 0x03, 0x01,
+};
+
+static const unsigned char ndivtab[] = {
+/* 2 */                            0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x78, 0xbc, 0x5e,
+/* 10 */       0x2f, 0x17, 0x0b, 0x85, 0xc2, 0xe1, 0x70, 0x38, 0x9c, 0x4e,
+/* 20 */       0xa7, 0xd3, 0xe9, 0xf4, 0xfa, 0xfd, 0xfe, 0x7f, 0xbf, 0xdf,
+/* 30 */       0xef, 0x77, 0x3b, 0x1d, 0x8e, 0xc7, 0xe3, 0x71, 0xb8, 0xdc,
+/* 40 */       0x6e, 0xb7, 0x5b, 0x2d, 0x16, 0x8b, 0xc5, 0xe2, 0xf1, 0xf8,
+/* 50 */       0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0x67, 0xb3, 0xd9, 0x6c, 0xb6,
+/* 60 */       0xdb, 0x6d, 0x36, 0x9b, 0x4d, 0x26, 0x13, 0x89, 0xc4, 0x62,
+/* 70 */       0xb1, 0xd8, 0xec, 0xf6, 0xfb, 0x7d, 0xbe, 0x5f, 0xaf, 0x57,
+/* 80 */       0x2b, 0x95, 0x4a, 0x25, 0x92, 0x49, 0xa4, 0x52, 0x29, 0x94,
+/* 90 */       0xca, 0x65, 0xb2, 0x59, 0x2c, 0x96, 0xcb, 0xe5, 0xf2, 0x79,
+/* 100 */      0x3c, 0x1e, 0x0f, 0x07, 0x83, 0x41, 0x20, 0x90, 0x48, 0x24,
+/* 110 */      0x12, 0x09, 0x84, 0x42, 0xa1, 0x50, 0x28, 0x14, 0x8a, 0x45,
+/* 120 */      0xa2, 0xd1, 0xe8, 0x74, 0xba, 0xdd, 0xee, 0xf7, 0x7b, 0x3d,
+/* 130 */      0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e,
+/* 140 */      0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98,
+/* 150 */      0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2,
+/* 160 */      0x69, 0xb4, 0xda, 0xed, 0x76, 0xbb, 0x5d, 0xae, 0xd7, 0x6b,
+/* 170 */      0xb5, 0x5a, 0xad, 0x56, 0xab, 0xd5, 0x6a, 0x35, 0x1a, 0x8d,
+/* 180 */      0x46, 0x23, 0x11, 0x88, 0x44, 0x22, 0x91, 0xc8, 0x64, 0x32,
+/* 190 */      0x19, 0x0c, 0x86, 0x43, 0x21, 0x10, 0x08, 0x04, 0x02, 0x81,
+/* 200 */      0x40, 0xa0, 0xd0, 0x68, 0x34, 0x9a, 0xcd, 0x66, 0x33, 0x99,
+/* 210 */      0x4c, 0xa6, 0x53, 0xa9, 0xd4, 0xea, 0x75, 0x3a, 0x9d, 0xce,
+/* 220 */      0xe7, 0xf3, 0xf9, 0x7c, 0x3e, 0x1f, 0x8f, 0x47, 0xa3, 0x51,
+/* 230 */      0xa8, 0x54, 0xaa, 0x55, 0x2a, 0x15, 0x0a, 0x05, 0x82, 0xc1,
+/* 240 */      0x60, 0xb0, 0x58, 0xac, 0xd6, 0xeb, 0xf5, 0x7a, 0xbd, 0xde,
+/* 250 */      0x6f, 0x37, 0x1b, 0x0d, 0x06, 0x03, 0x01,
+};
+
+#define REF_PERIOD_PS  9259    /* period of reference clock in ps */
+
+static int calc_pll(int period_ps, struct gxt4500_par *par)
+{
+       int m, n, pdiv1, pdiv2, postdiv;
+       int pll_period, best_error, t;
+
+       /* only deal with range 1MHz - 400MHz */
+       if (period_ps < 2500 || period_ps > 1000000)
+               return -1;
+
+       best_error = 1000000;
+       for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {
+               for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {
+                       postdiv = pdiv1 * pdiv2;
+                       pll_period = (period_ps + postdiv - 1) / postdiv;
+                       /* keep pll in range 500..1250 MHz */
+                       if (pll_period < 800 || pll_period > 2000)
+                               continue;
+                       for (m = 3; m <= 40; ++m) {
+                               n = REF_PERIOD_PS * m * postdiv / period_ps;
+                               if (n < 5 || n > 256)
+                                       continue;
+                               t = REF_PERIOD_PS * m * postdiv / n;
+                               t -= period_ps;
+                               if (t >= 0 && t < best_error) {
+                                       par->pll_m = m;
+                                       par->pll_n = n;
+                                       par->pll_pd1 = pdiv1;
+                                       par->pll_pd2 = pdiv2;
+                                       best_error = t;
+                               }
+                       }
+               }
+       }
+       if (best_error == 1000000)
+               return -1;
+       return 0;
+}
+
+static int calc_pixclock(struct gxt4500_par *par)
+{
+       return REF_PERIOD_PS * par->pll_m * par->pll_pd1 * par->pll_pd2
+               / par->pll_n;
+}
+
+static int gxt4500_var_to_par(struct fb_var_screeninfo *var,
+                             struct gxt4500_par *par)
+{
+       if (var->xres + var->xoffset > var->xres_virtual ||
+           var->yres + var->yoffset > var->yres_virtual ||
+           var->xres_virtual > 4096)
+               return -EINVAL;
+       if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+               return -EINVAL;
+
+       if (calc_pll(var->pixclock, par) < 0)
+               return -EINVAL;
+
+       switch (var->bits_per_pixel) {
+       case 32:
+               if (var->transp.length)
+                       par->pixfmt = DFA_PIX_32BIT;
+               else
+                       par->pixfmt = DFA_PIX_24BIT;
+               break;
+       case 24:
+               par->pixfmt = DFA_PIX_24BIT;
+               break;
+       case 16:
+               if (var->green.length == 5)
+                       par->pixfmt = DFA_PIX_16BIT_1555;
+               else
+                       par->pixfmt = DFA_PIX_16BIT_565;
+               break;
+       case 8:
+               par->pixfmt = DFA_PIX_8BIT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct fb_bitfield eightbits = {0, 8};
+static const struct fb_bitfield nobits = {0, 0};
+
+static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,
+                                 int pixfmt)
+{
+       var->bits_per_pixel = pixsize[pixfmt] * 8;
+       var->red = eightbits;
+       var->green = eightbits;
+       var->blue = eightbits;
+       var->transp = nobits;
+
+       switch (pixfmt) {
+       case DFA_PIX_16BIT_565:
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               break;
+       case DFA_PIX_16BIT_1555:
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               break;
+       case DFA_PIX_32BIT:
+               var->transp.length = 8;
+               break;
+       }
+       if (pixfmt != DFA_PIX_8BIT) {
+               var->green.offset = var->red.length;
+               var->blue.offset = var->green.offset + var->green.length;
+               if (var->transp.length)
+                       var->transp.offset =
+                               var->blue.offset + var->blue.length;
+       }
+}
+
+static int gxt4500_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct gxt4500_par par;
+       int err;
+
+       par = *(struct gxt4500_par *)info->par;
+       err = gxt4500_var_to_par(var, &par);
+       if (!err) {
+               var->pixclock = calc_pixclock(&par);
+               gxt4500_unpack_pixfmt(var, par.pixfmt);
+       }
+       return err;
+}
+
+static int gxt4500_set_par(struct fb_info *info)
+{
+       struct gxt4500_par *par = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       int err;
+       u32 ctrlreg;
+       unsigned int dfa_ctl, pixfmt, stride;
+       unsigned int wid_tiles, i;
+       unsigned int prefetch_pix, htot;
+       struct gxt4500_par save_par;
+
+       save_par = *par;
+       err = gxt4500_var_to_par(var, par);
+       if (err) {
+               *par = save_par;
+               return err;
+       }
+
+       /* turn off DTG for now */
+       ctrlreg = readreg(par, DTG_CONTROL);
+       ctrlreg &= ~(DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH);
+       writereg(par, DTG_CONTROL, ctrlreg);
+
+       /* set PLL registers */
+       writereg(par, PLL_M, mdivtab[par->pll_m - 1]);
+       writereg(par, PLL_N, ndivtab[par->pll_n - 2]);
+       writereg(par, PLL_POSTDIV,
+                ((8 - par->pll_pd1) << 3) | (8 - par->pll_pd2));
+       msleep(20);
+
+       /* turn off hardware cursor */
+       writereg(par, CURSOR_MODE, CURSOR_MODE_OFF);
+
+       /* reset raster engine */
+       writereg(par, CTRL_REG0, CR0_RASTER_RESET | (CR0_RASTER_RESET << 16));
+       udelay(10);
+       writereg(par, CTRL_REG0, CR0_RASTER_RESET << 16);
+
+       /* set display timing generator registers */
+       htot = var->xres + var->left_margin + var->right_margin +
+               var->hsync_len;
+       writereg(par, DTG_HORIZ_EXTENT, htot - 1);
+       writereg(par, DTG_HORIZ_DISPLAY, var->xres - 1);
+       writereg(par, DTG_HSYNC_START, var->xres + var->right_margin - 1);
+       writereg(par, DTG_HSYNC_END,
+                var->xres + var->right_margin + var->hsync_len - 1);
+       writereg(par, DTG_HSYNC_END_COMP,
+                var->xres + var->right_margin + var->hsync_len - 1);
+       writereg(par, DTG_VERT_EXTENT,
+                var->yres + var->upper_margin + var->lower_margin +
+                var->vsync_len - 1);
+       writereg(par, DTG_VERT_DISPLAY, var->yres - 1);
+       writereg(par, DTG_VSYNC_START, var->yres + var->lower_margin - 1);
+       writereg(par, DTG_VSYNC_END,
+                var->yres + var->lower_margin + var->vsync_len - 1);
+       prefetch_pix = 3300000 / var->pixclock;
+       if (prefetch_pix >= htot)
+               prefetch_pix = htot - 1;
+       writereg(par, DTG_VERT_SHORT, htot - prefetch_pix - 1);
+       ctrlreg |= DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH;
+       writereg(par, DTG_CONTROL, ctrlreg);
+
+       /* calculate stride in DFA aperture */
+       if (var->xres_virtual > 2048) {
+               stride = 4096;
+               dfa_ctl = DFA_FB_STRIDE_4k;
+       } else if (var->xres_virtual > 1024) {
+               stride = 2048;
+               dfa_ctl = DFA_FB_STRIDE_2k;
+       } else {
+               stride = 1024;
+               dfa_ctl = DFA_FB_STRIDE_1k;
+       }
+
+       /* Set up framebuffer definition */
+       wid_tiles = (var->xres_virtual + 63) >> 6;
+
+       /* XXX add proper FB allocation here someday */
+       writereg(par, FB_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+       writereg(par, REFRESH_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+       writereg(par, FB_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+       writereg(par, REFRESH_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
+       writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
+       writereg(par, REFRESH_SIZE, (var->xres << 16) | var->yres);
+
+       /* Set up framebuffer access by CPU */
+
+       pixfmt = par->pixfmt;
+       dfa_ctl |= DFA_FB_ENABLE | pixfmt;
+       writereg(par, DFA_FB_A, dfa_ctl);
+
+       /*
+        * Set up window attribute table.
+        * We set all WAT entries the same so it doesn't matter what the
+        * window ID (WID) plane contains.
+        */
+       for (i = 0; i < 32; ++i) {
+               writereg(par, WAT_FMT + (i << 4), watfmt[pixfmt]);
+               writereg(par, WAT_CMAP_OFFSET + (i << 4), 0);
+               writereg(par, WAT_CTRL + (i << 4), 0);
+               writereg(par, WAT_GAMMA_CTRL + (i << 4), WAT_GAMMA_DISABLE);
+       }
+
+       /* Set sync polarity etc. */
+       ctrlreg = readreg(par, SYNC_CTL) &
+               ~(SYNC_CTL_SYNC_ON_RGB | SYNC_CTL_HSYNC_INV |
+                 SYNC_CTL_VSYNC_INV);
+       if (var->sync & FB_SYNC_ON_GREEN)
+               ctrlreg |= SYNC_CTL_SYNC_ON_RGB;
+       if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+               ctrlreg |= SYNC_CTL_HSYNC_INV;
+       if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+               ctrlreg |= SYNC_CTL_VSYNC_INV;
+       writereg(par, SYNC_CTL, ctrlreg);
+
+       info->fix.line_length = stride * pixsize[pixfmt];
+       info->fix.visual = (pixfmt == DFA_PIX_8BIT)? FB_VISUAL_PSEUDOCOLOR:
+               FB_VISUAL_DIRECTCOLOR;
+
+       return 0;
+}
+
+static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
+                            unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info)
+{
+       u32 cmap_entry;
+       struct gxt4500_par *par = info->par;
+
+       if (reg > 1023)
+               return 1;
+       cmap_entry = ((transp & 0xff00) << 16) | ((blue & 0xff00) << 8) |
+               (green & 0xff00) | (red >> 8);
+       writereg(par, CMAP + reg * 4, cmap_entry);
+
+       if (reg < 16 && par->pixfmt != DFA_PIX_8BIT) {
+               u32 *pal = info->pseudo_palette;
+               u32 val = reg;
+               switch (par->pixfmt) {
+               case DFA_PIX_16BIT_565:
+                       val |= (reg << 11) | (reg << 6);
+                       break;
+               case DFA_PIX_16BIT_1555:
+                       val |= (reg << 10) | (reg << 5);
+                       break;
+               case DFA_PIX_32BIT:
+                       val |= (reg << 24);
+                       /* fall through */
+               case DFA_PIX_24BIT:
+                       val |= (reg << 16) | (reg << 8);
+                       break;
+               }
+               pal[reg] = val;
+       }
+
+       return 0;
+}
+
+static int gxt4500_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       struct gxt4500_par *par = info->par;
+
+       if (var->xoffset & 7)
+               return -EINVAL;
+       if (var->xoffset + var->xres > var->xres_virtual ||
+           var->yoffset + var->yres > var->yres_virtual)
+               return -EINVAL;
+
+       writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
+       return 0;
+}
+
+static int gxt4500_blank(int blank, struct fb_info *info)
+{
+       struct gxt4500_par *par = info->par;
+       int ctrl, dctl;
+
+       ctrl = readreg(par, SYNC_CTL);
+       ctrl &= ~(SYNC_CTL_SYNC_OFF | SYNC_CTL_HSYNC_OFF | SYNC_CTL_VSYNC_OFF);
+       dctl = readreg(par, DISP_CTL);
+       dctl |= DISP_CTL_OFF;
+       switch (blank) {
+       case FB_BLANK_UNBLANK:
+               dctl &= ~DISP_CTL_OFF;
+               break;
+       case FB_BLANK_POWERDOWN:
+               ctrl |= SYNC_CTL_SYNC_OFF;
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               ctrl |= SYNC_CTL_HSYNC_OFF;
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               ctrl |= SYNC_CTL_VSYNC_OFF;
+               break;
+       default: ;
+       }
+       writereg(par, SYNC_CTL, ctrl);
+       writereg(par, DISP_CTL, dctl);
+
+       return 0;
+}
+
+static const struct fb_fix_screeninfo gxt4500_fix __devinitdata = {
+       .id = "IBM GXT4500P",
+       .type = FB_TYPE_PACKED_PIXELS,
+       .visual = FB_VISUAL_PSEUDOCOLOR,
+       .xpanstep = 8,
+       .ypanstep = 1,
+       .mmio_len = 0x20000,
+};
+
+static struct fb_ops gxt4500_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = gxt4500_check_var,
+       .fb_set_par = gxt4500_set_par,
+       .fb_setcolreg = gxt4500_setcolreg,
+       .fb_pan_display = gxt4500_pan_display,
+       .fb_blank = gxt4500_blank,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+};
+
+/* PCI functions */
+static int __devinit gxt4500_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
+{
+       int err;
+       unsigned long reg_phys, fb_phys;
+       struct gxt4500_par *par;
+       struct fb_info *info;
+       struct fb_var_screeninfo var;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "gxt4500: cannot enable PCI device: %d\n",
+                       err);
+               return err;
+       }
+
+       reg_phys = pci_resource_start(pdev, 0);
+       if (!request_mem_region(reg_phys, pci_resource_len(pdev, 0),
+                               "gxt4500 regs")) {
+               dev_err(&pdev->dev, "gxt4500: cannot get registers\n");
+               goto err_nodev;
+       }
+
+       fb_phys = pci_resource_start(pdev, 1);
+       if (!request_mem_region(fb_phys, pci_resource_len(pdev, 1),
+                               "gxt4500 FB")) {
+               dev_err(&pdev->dev, "gxt4500: cannot get framebuffer\n");
+               goto err_free_regs;
+       }
+
+       info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
+       if (!info) {
+               dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record");
+               goto err_free_fb;
+       }
+       par = info->par;
+       info->fix = gxt4500_fix;
+       info->pseudo_palette = par->pseudo_palette;
+
+       info->fix.mmio_start = reg_phys;
+       par->regs = ioremap(reg_phys, pci_resource_len(pdev, 0));
+       if (!par->regs) {
+               dev_err(&pdev->dev, "gxt4500: cannot map registers\n");
+               goto err_free_all;
+       }
+
+       info->fix.smem_start = fb_phys;
+       info->fix.smem_len = pci_resource_len(pdev, 1);
+       info->screen_base = ioremap(fb_phys, pci_resource_len(pdev, 1));
+       if (!info->screen_base) {
+               dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n");
+               goto err_unmap_regs;
+       }
+
+       pci_set_drvdata(pdev, info);
+
+       /* Set byte-swapping for DFA aperture for all pixel sizes */
+       pci_write_config_dword(pdev, CFG_ENDIAN0, 0x333300);
+
+       info->fbops = &gxt4500_ops;
+       info->flags = FBINFO_FLAG_DEFAULT;
+
+       err = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (err) {
+               dev_err(&pdev->dev, "gxt4500: cannot allocate cmap\n");
+               goto err_unmap_all;
+       }
+
+       gxt4500_blank(FB_BLANK_UNBLANK, info);
+
+       if (!fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8)) {
+               dev_err(&pdev->dev, "gxt4500: cannot find valid video mode\n");
+               goto err_free_cmap;
+       }
+       info->var = var;
+       if (gxt4500_set_par(info)) {
+               printk(KERN_ERR "gxt4500: cannot set video mode\n");
+               goto err_free_cmap;
+       }
+
+       if (register_framebuffer(info) < 0) {
+               dev_err(&pdev->dev, "gxt4500: cannot register framebuffer\n");
+               goto err_free_cmap;
+       }
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+              info->node, info->fix.id);
+
+       return 0;
+
+ err_free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+ err_unmap_all:
+       iounmap(info->screen_base);
+ err_unmap_regs:
+       iounmap(par->regs);
+ err_free_all:
+       framebuffer_release(info);
+ err_free_fb:
+       release_mem_region(fb_phys, pci_resource_len(pdev, 1));
+ err_free_regs:
+       release_mem_region(reg_phys, pci_resource_len(pdev, 0));
+ err_nodev:
+       return -ENODEV;
+}
+
+static void __devexit gxt4500_remove(struct pci_dev *pdev)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+       struct gxt4500_par *par;
+
+       if (!info)
+               return;
+       par = info->par;
+       unregister_framebuffer(info);
+       fb_dealloc_cmap(&info->cmap);
+       iounmap(par->regs);
+       iounmap(info->screen_base);
+       release_mem_region(pci_resource_start(pdev, 0),
+                          pci_resource_len(pdev, 0));
+       release_mem_region(pci_resource_start(pdev, 1),
+                          pci_resource_len(pdev, 1));
+       framebuffer_release(info);
+}
+
+/* supported chipsets */
+static const struct pci_device_id gxt4500_pci_tbl[] = {
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, gxt4500_pci_tbl);
+
+static struct pci_driver gxt4500_driver = {
+       .name = "gxt4500",
+       .id_table = gxt4500_pci_tbl,
+       .probe = gxt4500_probe,
+       .remove = __devexit_p(gxt4500_remove),
+};
+
+static int __devinit gxt4500_init(void)
+{
+#ifndef MODULE
+       if (fb_get_options("gxt4500", &mode_option))
+               return -ENODEV;
+#endif
+
+       return pci_register_driver(&gxt4500_driver);
+}
+module_init(gxt4500_init);
+
+static void __exit gxt4500_exit(void)
+{
+       pci_unregister_driver(&gxt4500_driver);
+}
+module_exit(gxt4500_exit);
+
+MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
+MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P");
+MODULE_LICENSE("GPL");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
index 517860f2d75b0d575e65af71f54745840a3a28ad..d1f1b54d3108c6bb52ebc25ce285451eecab8e9b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/hash.h>
 #include <linux/suspend.h>
 #include <linux/buffer_head.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/bio.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
@@ -724,20 +725,21 @@ int __set_page_dirty_buffers(struct page *page)
        }
        spin_unlock(&mapping->private_lock);
 
-       if (!TestSetPageDirty(page)) {
-               write_lock_irq(&mapping->tree_lock);
-               if (page->mapping) {    /* Race with truncate? */
-                       if (mapping_cap_account_dirty(mapping))
-                               __inc_zone_page_state(page, NR_FILE_DIRTY);
-                       radix_tree_tag_set(&mapping->page_tree,
-                                               page_index(page),
-                                               PAGECACHE_TAG_DIRTY);
+       if (TestSetPageDirty(page))
+               return 0;
+
+       write_lock_irq(&mapping->tree_lock);
+       if (page->mapping) {    /* Race with truncate? */
+               if (mapping_cap_account_dirty(mapping)) {
+                       __inc_zone_page_state(page, NR_FILE_DIRTY);
+                       task_io_account_write(PAGE_CACHE_SIZE);
                }
-               write_unlock_irq(&mapping->tree_lock);
-               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-               return 1;
+               radix_tree_tag_set(&mapping->page_tree,
+                               page_index(page), PAGECACHE_TAG_DIRTY);
        }
-       return 0;
+       write_unlock_irq(&mapping->tree_lock);
+       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+       return 1;
 }
 EXPORT_SYMBOL(__set_page_dirty_buffers);
 
@@ -2851,8 +2853,13 @@ int try_to_free_buffers(struct page *page)
                 * could encounter a non-uptodate page, which is unresolvable.
                 * This only applies in the rare case where try_to_free_buffers
                 * succeeds but the page is not freed.
+                *
+                * Also, during truncate, discard_buffer will have marked all
+                * the page's buffers clean.  We discover that here and clean
+                * the page also.
                 */
-               clear_page_dirty(page);
+               if (test_clear_page_dirty(page))
+                       task_io_account_cancelled_write(PAGE_CACHE_SIZE);
        }
 out:
        if (buffers_to_free) {
index 1aa95a50cac25baf08cf856ecdd0bf60e662344c..0f05cab5d24ad245ec6f42bf8efa7e44dad58bc2 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pagevec.h>
 #include <linux/smp_lock.h>
 #include <linux/writeback.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/delay.h>
 #include <asm/div64.h>
 #include "cifsfs.h"
@@ -1812,6 +1813,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        cFYI(1, ("Read error in readpages: %d", rc));
                        break;
                } else if (bytes_read > 0) {
+                       task_io_account_read(bytes_read);
                        pSMBr = (struct smb_com_read_rsp *)smb_read_data;
                        cifs_copy_cache_pages(mapping, page_list, bytes_read,
                                smb_read_data + 4 /* RFC1001 hdr */ +
index b766964a625c6f8c4be2a194fddf286a969d13a2..0ec70e3cee0a6113e24b9282250dbcb950e144f1 100644 (file)
@@ -1679,19 +1679,19 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
 {
        fd_set_bits fds;
        char *bits;
-       int size, max_fdset, ret = -EINVAL;
+       int size, max_fds, ret = -EINVAL;
        struct fdtable *fdt;
 
        if (n < 0)
                goto out_nofds;
 
-       /* max_fdset can increase, so grab it once to avoid race */
+       /* max_fds can increase, so grab it once to avoid race */
        rcu_read_lock();
        fdt = files_fdtable(current->files);
-       max_fdset = fdt->max_fdset;
+       max_fds = fdt->max_fds;
        rcu_read_unlock();
-       if (n > max_fdset)
-               n = max_fdset;
+       if (n > max_fds)
+               n = max_fds;
 
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
index 5981e17f46f051afa98ec0b7af67c1b25a0dc897..d9d0833444f59da15dc8be42420c13366429d402 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/bio.h>
 #include <linux/wait.h>
 #include <linux/err.h>
@@ -121,8 +122,7 @@ struct dio {
 
        /* BIO completion state */
        spinlock_t bio_lock;            /* protects BIO fields below */
-       int bio_count;                  /* nr bios to be completed */
-       int bios_in_flight;             /* nr bios in flight */
+       unsigned long refcount;         /* direct_io_worker() and bios */
        struct bio *bio_list;           /* singly linked via bi_private */
        struct task_struct *waiter;     /* waiting task (NULL if none) */
 
@@ -209,76 +209,55 @@ static struct page *dio_get_page(struct dio *dio)
        return dio->pages[dio->head++];
 }
 
-/*
- * Called when all DIO BIO I/O has been completed - let the filesystem
- * know, if it registered an interest earlier via get_block.  Pass the
- * private field of the map buffer_head so that filesystems can use it
- * to hold additional state between get_block calls and dio_complete.
- */
-static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
-{
-       if (dio->end_io && dio->result)
-               dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private);
-       if (dio->lock_type == DIO_LOCKING)
-               /* lockdep: non-owner release */
-               up_read_non_owner(&dio->inode->i_alloc_sem);
-}
-
-/*
- * Called when a BIO has been processed.  If the count goes to zero then IO is
- * complete and we can signal this to the AIO layer.
+/**
+ * dio_complete() - called when all DIO BIO I/O has been completed
+ * @offset: the byte offset in the file of the completed operation
+ *
+ * This releases locks as dictated by the locking type, lets interested parties
+ * know that a DIO operation has completed, and calculates the resulting return
+ * code for the operation.
+ *
+ * It lets the filesystem know if it registered an interest earlier via
+ * get_block.  Pass the private field of the map buffer_head so that
+ * filesystems can use it to hold additional state between get_block calls and
+ * dio_complete.
  */
-static void finished_one_bio(struct dio *dio)
+static int dio_complete(struct dio *dio, loff_t offset, int ret)
 {
-       unsigned long flags;
+       ssize_t transferred = 0;
 
-       spin_lock_irqsave(&dio->bio_lock, flags);
-       if (dio->bio_count == 1) {
-               if (dio->is_async) {
-                       ssize_t transferred;
-                       loff_t offset;
-
-                       /*
-                        * Last reference to the dio is going away.
-                        * Drop spinlock and complete the DIO.
-                        */
-                       spin_unlock_irqrestore(&dio->bio_lock, flags);
+       /*
+        * AIO submission can race with bio completion to get here while
+        * expecting to have the last io completed by bio completion.
+        * In that case -EIOCBQUEUED is in fact not an error we want
+        * to preserve through this call.
+        */
+       if (ret == -EIOCBQUEUED)
+               ret = 0;
 
-                       /* Check for short read case */
-                       transferred = dio->result;
-                       offset = dio->iocb->ki_pos;
+       if (dio->result) {
+               transferred = dio->result;
 
-                       if ((dio->rw == READ) &&
-                           ((offset + transferred) > dio->i_size))
-                               transferred = dio->i_size - offset;
+               /* Check for short read case */
+               if ((dio->rw == READ) && ((offset + transferred) > dio->i_size))
+                       transferred = dio->i_size - offset;
+       }
 
-                       /* check for error in completion path */
-                       if (dio->io_error)
-                               transferred = dio->io_error;
+       if (dio->end_io && dio->result)
+               dio->end_io(dio->iocb, offset, transferred,
+                           dio->map_bh.b_private);
+       if (dio->lock_type == DIO_LOCKING)
+               /* lockdep: non-owner release */
+               up_read_non_owner(&dio->inode->i_alloc_sem);
 
-                       dio_complete(dio, offset, transferred);
+       if (ret == 0)
+               ret = dio->page_errors;
+       if (ret == 0)
+               ret = dio->io_error;
+       if (ret == 0)
+               ret = transferred;
 
-                       /* Complete AIO later if falling back to buffered i/o */
-                       if (dio->result == dio->size ||
-                               ((dio->rw == READ) && dio->result)) {
-                               aio_complete(dio->iocb, transferred, 0);
-                               kfree(dio);
-                               return;
-                       } else {
-                               /*
-                                * Falling back to buffered
-                                */
-                               spin_lock_irqsave(&dio->bio_lock, flags);
-                               dio->bio_count--;
-                               if (dio->waiter)
-                                       wake_up_process(dio->waiter);
-                               spin_unlock_irqrestore(&dio->bio_lock, flags);
-                               return;
-                       }
-               }
-       }
-       dio->bio_count--;
-       spin_unlock_irqrestore(&dio->bio_lock, flags);
+       return ret;
 }
 
 static int dio_bio_complete(struct dio *dio, struct bio *bio);
@@ -288,12 +267,27 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio);
 static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error)
 {
        struct dio *dio = bio->bi_private;
+       unsigned long remaining;
+       unsigned long flags;
 
        if (bio->bi_size)
                return 1;
 
        /* cleanup the bio */
        dio_bio_complete(dio, bio);
+
+       spin_lock_irqsave(&dio->bio_lock, flags);
+       remaining = --dio->refcount;
+       if (remaining == 1 && dio->waiter)
+               wake_up_process(dio->waiter);
+       spin_unlock_irqrestore(&dio->bio_lock, flags);
+
+       if (remaining == 0) {
+               int ret = dio_complete(dio, dio->iocb->ki_pos, 0);
+               aio_complete(dio->iocb, ret, 0);
+               kfree(dio);
+       }
+
        return 0;
 }
 
@@ -315,8 +309,7 @@ static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
        spin_lock_irqsave(&dio->bio_lock, flags);
        bio->bi_private = dio->bio_list;
        dio->bio_list = bio;
-       dio->bios_in_flight--;
-       if (dio->waiter && dio->bios_in_flight == 0)
+       if (--dio->refcount == 1 && dio->waiter)
                wake_up_process(dio->waiter);
        spin_unlock_irqrestore(&dio->bio_lock, flags);
        return 0;
@@ -347,6 +340,8 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
  * In the AIO read case we speculatively dirty the pages before starting IO.
  * During IO completion, any of these pages which happen to have been written
  * back will be redirtied by bio_check_pages_dirty().
+ *
+ * bios hold a dio reference between submit_bio and ->end_io.
  */
 static void dio_bio_submit(struct dio *dio)
 {
@@ -354,12 +349,14 @@ static void dio_bio_submit(struct dio *dio)
        unsigned long flags;
 
        bio->bi_private = dio;
+
        spin_lock_irqsave(&dio->bio_lock, flags);
-       dio->bio_count++;
-       dio->bios_in_flight++;
+       dio->refcount++;
        spin_unlock_irqrestore(&dio->bio_lock, flags);
+
        if (dio->is_async && dio->rw == READ)
                bio_set_pages_dirty(bio);
+
        submit_bio(dio->rw, bio);
 
        dio->bio = NULL;
@@ -376,28 +373,37 @@ static void dio_cleanup(struct dio *dio)
 }
 
 /*
- * Wait for the next BIO to complete.  Remove it and return it.
+ * Wait for the next BIO to complete.  Remove it and return it.  NULL is
+ * returned once all BIOs have been completed.  This must only be called once
+ * all bios have been issued so that dio->refcount can only decrease.  This
+ * requires that that the caller hold a reference on the dio.
  */
 static struct bio *dio_await_one(struct dio *dio)
 {
        unsigned long flags;
-       struct bio *bio;
+       struct bio *bio = NULL;
 
        spin_lock_irqsave(&dio->bio_lock, flags);
-       while (dio->bio_list == NULL) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               if (dio->bio_list == NULL) {
-                       dio->waiter = current;
-                       spin_unlock_irqrestore(&dio->bio_lock, flags);
-                       blk_run_address_space(dio->inode->i_mapping);
-                       io_schedule();
-                       spin_lock_irqsave(&dio->bio_lock, flags);
-                       dio->waiter = NULL;
-               }
-               set_current_state(TASK_RUNNING);
+
+       /*
+        * Wait as long as the list is empty and there are bios in flight.  bio
+        * completion drops the count, maybe adds to the list, and wakes while
+        * holding the bio_lock so we don't need set_current_state()'s barrier
+        * and can call it after testing our condition.
+        */
+       while (dio->refcount > 1 && dio->bio_list == NULL) {
+               __set_current_state(TASK_UNINTERRUPTIBLE);
+               dio->waiter = current;
+               spin_unlock_irqrestore(&dio->bio_lock, flags);
+               io_schedule();
+               /* wake up sets us TASK_RUNNING */
+               spin_lock_irqsave(&dio->bio_lock, flags);
+               dio->waiter = NULL;
+       }
+       if (dio->bio_list) {
+               bio = dio->bio_list;
+               dio->bio_list = bio->bi_private;
        }
-       bio = dio->bio_list;
-       dio->bio_list = bio->bi_private;
        spin_unlock_irqrestore(&dio->bio_lock, flags);
        return bio;
 }
@@ -426,34 +432,24 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
                }
                bio_put(bio);
        }
-       finished_one_bio(dio);
        return uptodate ? 0 : -EIO;
 }
 
 /*
- * Wait on and process all in-flight BIOs.
+ * Wait on and process all in-flight BIOs.  This must only be called once
+ * all bios have been issued so that the refcount can only decrease.
+ * This just waits for all bios to make it through dio_bio_complete.  IO
+ * errors are propogated through dio->io_error and should be propogated via
+ * dio_complete().
  */
-static int dio_await_completion(struct dio *dio)
+static void dio_await_completion(struct dio *dio)
 {
-       int ret = 0;
-
-       if (dio->bio)
-               dio_bio_submit(dio);
-
-       /*
-        * The bio_lock is not held for the read of bio_count.
-        * This is ok since it is the dio_bio_complete() that changes
-        * bio_count.
-        */
-       while (dio->bio_count) {
-               struct bio *bio = dio_await_one(dio);
-               int ret2;
-
-               ret2 = dio_bio_complete(dio, bio);
-               if (ret == 0)
-                       ret = ret2;
-       }
-       return ret;
+       struct bio *bio;
+       do {
+               bio = dio_await_one(dio);
+               if (bio)
+                       dio_bio_complete(dio, bio);
+       } while (bio);
 }
 
 /*
@@ -675,6 +671,13 @@ submit_page_section(struct dio *dio, struct page *page,
 {
        int ret = 0;
 
+       if (dio->rw & WRITE) {
+               /*
+                * Read accounting is performed in submit_bio()
+                */
+               task_io_account_write(len);
+       }
+
        /*
         * Can we just grow the current page's presence in the dio?
         */
@@ -953,6 +956,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        struct dio *dio)
 {
        unsigned long user_addr; 
+       unsigned long flags;
        int seg;
        ssize_t ret = 0;
        ssize_t ret2;
@@ -983,17 +987,8 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        dio->iocb = iocb;
        dio->i_size = i_size_read(inode);
 
-       /*
-        * BIO completion state.
-        *
-        * ->bio_count starts out at one, and we decrement it to zero after all
-        * BIOs are submitted.  This to avoid the situation where a really fast
-        * (or synchronous) device could take the count to zero while we're
-        * still submitting BIOs.
-        */
-       dio->bio_count = 1;
-       dio->bios_in_flight = 0;
        spin_lock_init(&dio->bio_lock);
+       dio->refcount = 1;
        dio->bio_list = NULL;
        dio->waiter = NULL;
 
@@ -1069,6 +1064,9 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
        if (dio->bio)
                dio_bio_submit(dio);
 
+       /* All IO is now issued, send it on its way */
+       blk_run_address_space(inode->i_mapping);
+
        /*
         * It is possible that, we return short IO due to end of file.
         * In that case, we need to release all the pages we got hold on.
@@ -1084,74 +1082,41 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
                mutex_unlock(&dio->inode->i_mutex);
 
        /*
-        * OK, all BIOs are submitted, so we can decrement bio_count to truly
-        * reflect the number of to-be-processed BIOs.
+        * The only time we want to leave bios in flight is when a successful
+        * partial aio read or full aio write have been setup.  In that case
+        * bio completion will call aio_complete.  The only time it's safe to
+        * call aio_complete is when we return -EIOCBQUEUED, so we key on that.
+        * This had *better* be the only place that raises -EIOCBQUEUED.
         */
-       if (dio->is_async) {
-               int should_wait = 0;
+       BUG_ON(ret == -EIOCBQUEUED);
+       if (dio->is_async && ret == 0 && dio->result &&
+           ((rw & READ) || (dio->result == dio->size)))
+               ret = -EIOCBQUEUED;
 
-               if (dio->result < dio->size && (rw & WRITE)) {
-                       dio->waiter = current;
-                       should_wait = 1;
-               }
-               if (ret == 0)
-                       ret = dio->result;
-               finished_one_bio(dio);          /* This can free the dio */
-               blk_run_address_space(inode->i_mapping);
-               if (should_wait) {
-                       unsigned long flags;
-                       /*
-                        * Wait for already issued I/O to drain out and
-                        * release its references to user-space pages
-                        * before returning to fallback on buffered I/O
-                        */
-
-                       spin_lock_irqsave(&dio->bio_lock, flags);
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       while (dio->bio_count) {
-                               spin_unlock_irqrestore(&dio->bio_lock, flags);
-                               io_schedule();
-                               spin_lock_irqsave(&dio->bio_lock, flags);
-                               set_current_state(TASK_UNINTERRUPTIBLE);
-                       }
-                       spin_unlock_irqrestore(&dio->bio_lock, flags);
-                       set_current_state(TASK_RUNNING);
-                       kfree(dio);
-               }
-       } else {
-               ssize_t transferred = 0;
-
-               finished_one_bio(dio);
-               ret2 = dio_await_completion(dio);
-               if (ret == 0)
-                       ret = ret2;
-               if (ret == 0)
-                       ret = dio->page_errors;
-               if (dio->result) {
-                       loff_t i_size = i_size_read(inode);
-
-                       transferred = dio->result;
-                       /*
-                        * Adjust the return value if the read crossed a
-                        * non-block-aligned EOF.
-                        */
-                       if (rw == READ && (offset + transferred > i_size))
-                               transferred = i_size - offset;
-               }
-               dio_complete(dio, offset, transferred);
-               if (ret == 0)
-                       ret = transferred;
+       if (ret != -EIOCBQUEUED)
+               dio_await_completion(dio);
 
-               /* We could have also come here on an AIO file extend */
-               if (!is_sync_kiocb(iocb) && (rw & WRITE) &&
-                   ret >= 0 && dio->result == dio->size)
-                       /*
-                        * For AIO writes where we have completed the
-                        * i/o, we have to mark the the aio complete.
-                        */
-                       aio_complete(iocb, ret, 0);
+       /*
+        * Sync will always be dropping the final ref and completing the
+        * operation.  AIO can if it was a broken operation described above or
+        * in fact if all the bios race to complete before we get here.  In
+        * that case dio_complete() translates the EIOCBQUEUED into the proper
+        * return code that the caller will hand to aio_complete().
+        *
+        * This is managed by the bio_lock instead of being an atomic_t so that
+        * completion paths can drop their ref and use the remaining count to
+        * decide to wake the submission path atomically.
+        */
+       spin_lock_irqsave(&dio->bio_lock, flags);
+       ret2 = --dio->refcount;
+       spin_unlock_irqrestore(&dio->bio_lock, flags);
+       BUG_ON(!dio->is_async && ret2 != 0);
+       if (ret2 == 0) {
+               ret = dio_complete(dio, offset, ret);
                kfree(dio);
-       }
+       } else
+               BUG_ON(ret != -EIOCBQUEUED);
+
        return ret;
 }
 
index 12d8cd461b412378fe8d16b8e39c7a330770a649..11fe93f7363c9dfb0cd05f52992ac0e6dd6bba9c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -783,7 +783,7 @@ static void flush_old_files(struct files_struct * files)
                j++;
                i = j * __NFDBITS;
                fdt = files_fdtable(files);
-               if (i >= fdt->max_fds || i >= fdt->max_fdset)
+               if (i >= fdt->max_fds)
                        break;
                set = fdt->close_on_exec->fds_bits[j];
                if (!set)
index 2bdaef35da5479a406aa1eb658eba498c145c4c7..8e382a5d51bd6f757bd694344465de0711d4afb2 100644 (file)
@@ -77,10 +77,9 @@ repeat:
                start = files->next_fd;
 
        newfd = start;
-       if (start < fdt->max_fdset) {
+       if (start < fdt->max_fds)
                newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
-                       fdt->max_fdset, start);
-       }
+                                          fdt->max_fds, start);
        
        error = -EMFILE;
        if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
index 51aef675470fb64984733fe9a710adc7cb6b980a..857fa49e984ca025b36a653aced4af23d56f20b5 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -32,46 +32,28 @@ struct fdtable_defer {
  */
 static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list);
 
-
-/*
- * Allocate an fd array, using kmalloc or vmalloc.
- * Note: the array isn't cleared at allocation time.
- */
-struct file ** alloc_fd_array(int num)
+static inline void * alloc_fdmem(unsigned int size)
 {
-       struct file **new_fds;
-       int size = num * sizeof(struct file *);
-
        if (size <= PAGE_SIZE)
-               new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
-       else 
-               new_fds = (struct file **) vmalloc(size);
-       return new_fds;
+               return kmalloc(size, GFP_KERNEL);
+       else
+               return vmalloc(size);
 }
 
-void free_fd_array(struct file **array, int num)
+static inline void free_fdarr(struct fdtable *fdt)
 {
-       int size = num * sizeof(struct file *);
-
-       if (!array) {
-               printk (KERN_ERR "free_fd_array: array = 0 (num = %d)\n", num);
-               return;
-       }
-
-       if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
-               return;
-       else if (size <= PAGE_SIZE)
-               kfree(array);
+       if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *)))
+               kfree(fdt->fd);
        else
-               vfree(array);
+               vfree(fdt->fd);
 }
 
-static void __free_fdtable(struct fdtable *fdt)
+static inline void free_fdset(struct fdtable *fdt)
 {
-       free_fdset(fdt->open_fds, fdt->max_fdset);
-       free_fdset(fdt->close_on_exec, fdt->max_fdset);
-       free_fd_array(fdt->fd, fdt->max_fds);
-       kfree(fdt);
+       if (fdt->max_fds <= (PAGE_SIZE * BITS_PER_BYTE / 2))
+               kfree(fdt->open_fds);
+       else
+               vfree(fdt->open_fds);
 }
 
 static void free_fdtable_work(struct work_struct *work)
@@ -86,41 +68,32 @@ static void free_fdtable_work(struct work_struct *work)
        spin_unlock_bh(&f->lock);
        while(fdt) {
                struct fdtable *next = fdt->next;
-               __free_fdtable(fdt);
+               vfree(fdt->fd);
+               free_fdset(fdt);
+               kfree(fdt);
                fdt = next;
        }
 }
 
-static void free_fdtable_rcu(struct rcu_head *rcu)
+void free_fdtable_rcu(struct rcu_head *rcu)
 {
        struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
-       int fdset_size, fdarray_size;
        struct fdtable_defer *fddef;
 
        BUG_ON(!fdt);
-       fdset_size = fdt->max_fdset / 8;
-       fdarray_size = fdt->max_fds * sizeof(struct file *);
 
-       if (fdt->free_files) {
+       if (fdt->max_fds <= NR_OPEN_DEFAULT) {
                /*
-                * The this fdtable was embedded in the files structure
-                * and the files structure itself was getting destroyed.
-                * It is now safe to free the files structure.
+                * This fdtable is embedded in the files structure and that
+                * structure itself is getting destroyed.
                 */
-               kmem_cache_free(files_cachep, fdt->free_files);
+               kmem_cache_free(files_cachep,
+                               container_of(fdt, struct files_struct, fdtab));
                return;
        }
-       if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE &&
-               fdt->max_fds <= NR_OPEN_DEFAULT) {
-               /*
-                * The fdtable was embedded
-                */
-               return;
-       }
-       if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
-               kfree(fdt->open_fds);
-               kfree(fdt->close_on_exec);
+       if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) {
                kfree(fdt->fd);
+               kfree(fdt->open_fds);
                kfree(fdt);
        } else {
                fddef = &get_cpu_var(fdtable_defer_list);
@@ -134,136 +107,74 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
        }
 }
 
-void free_fdtable(struct fdtable *fdt)
-{
-       if (fdt->free_files ||
-               fdt->max_fdset > EMBEDDED_FD_SET_SIZE ||
-               fdt->max_fds > NR_OPEN_DEFAULT)
-               call_rcu(&fdt->rcu, free_fdtable_rcu);
-}
-
 /*
  * Expand the fdset in the files_struct.  Called with the files spinlock
  * held for write.
  */
-static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
+static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
 {
-       int i;
-       int count;
-
-       BUG_ON(nfdt->max_fdset < fdt->max_fdset);
-       BUG_ON(nfdt->max_fds < fdt->max_fds);
-       /* Copy the existing tables and install the new pointers */
-
-       i = fdt->max_fdset / (sizeof(unsigned long) * 8);
-       count = (nfdt->max_fdset - fdt->max_fdset) / 8;
+       unsigned int cpy, set;
 
-       /*
-        * Don't copy the entire array if the current fdset is
-        * not yet initialised.
-        */
-       if (i) {
-               memcpy (nfdt->open_fds, fdt->open_fds,
-                                               fdt->max_fdset/8);
-               memcpy (nfdt->close_on_exec, fdt->close_on_exec,
-                                               fdt->max_fdset/8);
-               memset (&nfdt->open_fds->fds_bits[i], 0, count);
-               memset (&nfdt->close_on_exec->fds_bits[i], 0, count);
-       }
-
-       /* Don't copy/clear the array if we are creating a new
-          fd array for fork() */
-       if (fdt->max_fds) {
-               memcpy(nfdt->fd, fdt->fd,
-                       fdt->max_fds * sizeof(struct file *));
-               /* clear the remainder of the array */
-               memset(&nfdt->fd[fdt->max_fds], 0,
-                      (nfdt->max_fds - fdt->max_fds) *
-                                       sizeof(struct file *));
-       }
-}
-
-/*
- * Allocate an fdset array, using kmalloc or vmalloc.
- * Note: the array isn't cleared at allocation time.
- */
-fd_set * alloc_fdset(int num)
-{
-       fd_set *new_fdset;
-       int size = num / 8;
+       BUG_ON(nfdt->max_fds < ofdt->max_fds);
+       if (ofdt->max_fds == 0)
+               return;
 
-       if (size <= PAGE_SIZE)
-               new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
-       else
-               new_fdset = (fd_set *) vmalloc(size);
-       return new_fdset;
+       cpy = ofdt->max_fds * sizeof(struct file *);
+       set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *);
+       memcpy(nfdt->fd, ofdt->fd, cpy);
+       memset((char *)(nfdt->fd) + cpy, 0, set);
+
+       cpy = ofdt->max_fds / BITS_PER_BYTE;
+       set = (nfdt->max_fds - ofdt->max_fds) / BITS_PER_BYTE;
+       memcpy(nfdt->open_fds, ofdt->open_fds, cpy);
+       memset((char *)(nfdt->open_fds) + cpy, 0, set);
+       memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy);
+       memset((char *)(nfdt->close_on_exec) + cpy, 0, set);
 }
 
-void free_fdset(fd_set *array, int num)
+static struct fdtable * alloc_fdtable(unsigned int nr)
 {
-       if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */
-               return;
-       else if (num <= 8 * PAGE_SIZE)
-               kfree(array);
-       else
-               vfree(array);
-}
+       struct fdtable *fdt;
+       char *data;
 
-static struct fdtable *alloc_fdtable(int nr)
-{
-       struct fdtable *fdt = NULL;
-       int nfds = 0;
-       fd_set *new_openset = NULL, *new_execset = NULL;
-       struct file **new_fds;
+       /*
+        * Figure out how many fds we actually want to support in this fdtable.
+        * Allocation steps are keyed to the size of the fdarray, since it
+        * grows far faster than any of the other dynamic data. We try to fit
+        * the fdarray into comfortable page-tuned chunks: starting at 1024B
+        * and growing in powers of two from there on.
+        */
+       nr /= (1024 / sizeof(struct file *));
+       nr = roundup_pow_of_two(nr + 1);
+       nr *= (1024 / sizeof(struct file *));
+       if (nr > NR_OPEN)
+               nr = NR_OPEN;
 
-       fdt = kzalloc(sizeof(*fdt), GFP_KERNEL);
+       fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
        if (!fdt)
-               goto out;
-
-       nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
-       if (nfds > NR_OPEN)
-               nfds = NR_OPEN;
+               goto out;
+       fdt->max_fds = nr;
+       data = alloc_fdmem(nr * sizeof(struct file *));
+       if (!data)
+               goto out_fdt;
+       fdt->fd = (struct file **)data;
+       data = alloc_fdmem(max_t(unsigned int,
+                                2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES));
+       if (!data)
+               goto out_arr;
+       fdt->open_fds = (fd_set *)data;
+       data += nr / BITS_PER_BYTE;
+       fdt->close_on_exec = (fd_set *)data;
+       INIT_RCU_HEAD(&fdt->rcu);
+       fdt->next = NULL;
 
-       new_openset = alloc_fdset(nfds);
-       new_execset = alloc_fdset(nfds);
-       if (!new_openset || !new_execset)
-               goto out;
-       fdt->open_fds = new_openset;
-       fdt->close_on_exec = new_execset;
-       fdt->max_fdset = nfds;
-
-       nfds = NR_OPEN_DEFAULT;
-       /*
-        * Expand to the max in easy steps, and keep expanding it until
-        * we have enough for the requested fd array size.
-        */
-       do {
-#if NR_OPEN_DEFAULT < 256
-               if (nfds < 256)
-                       nfds = 256;
-               else
-#endif
-               if (nfds < (PAGE_SIZE / sizeof(struct file *)))
-                       nfds = PAGE_SIZE / sizeof(struct file *);
-               else {
-                       nfds = nfds * 2;
-                       if (nfds > NR_OPEN)
-                               nfds = NR_OPEN;
-               }
-       } while (nfds <= nr);
-       new_fds = alloc_fd_array(nfds);
-       if (!new_fds)
-               goto out2;
-       fdt->fd = new_fds;
-       fdt->max_fds = nfds;
-       fdt->free_files = NULL;
        return fdt;
-out2:
-       nfds = fdt->max_fdset;
-out:
-       free_fdset(new_openset, nfds);
-       free_fdset(new_execset, nfds);
+
+out_arr:
+       free_fdarr(fdt);
+out_fdt:
        kfree(fdt);
+out:
        return NULL;
 }
 
@@ -290,14 +201,17 @@ static int expand_fdtable(struct files_struct *files, int nr)
         * we dropped the lock
         */
        cur_fdt = files_fdtable(files);
-       if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
+       if (nr >= cur_fdt->max_fds) {
                /* Continue as planned */
                copy_fdtable(new_fdt, cur_fdt);
                rcu_assign_pointer(files->fdt, new_fdt);
-               free_fdtable(cur_fdt);
+               if (cur_fdt->max_fds > NR_OPEN_DEFAULT)
+                       call_rcu(&cur_fdt->rcu, free_fdtable_rcu);
        } else {
                /* Somebody else expanded, so undo our attempt */
-               __free_fdtable(new_fdt);
+               free_fdarr(new_fdt);
+               free_fdset(new_fdt);
+               kfree(new_fdt);
        }
        return 1;
 }
@@ -316,11 +230,10 @@ int expand_files(struct files_struct *files, int nr)
 
        fdt = files_fdtable(files);
        /* Do we need to expand? */
-       if (nr < fdt->max_fdset && nr < fdt->max_fds)
+       if (nr < fdt->max_fds)
                return 0;
        /* Can we expand? */
-       if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
-           nr >= NR_OPEN)
+       if (nr >= NR_OPEN)
                return -EMFILE;
 
        /* All good, so we try */
index d38e0d575e48d3d0554384a52277be8f4469b1c0..cceaf57e37781304df0b553ca2f8e9957fd65ecb 100644 (file)
@@ -55,7 +55,7 @@ get_transaction(journal_t *journal, transaction_t *transaction)
        spin_lock_init(&transaction->t_handle_lock);
 
        /* Set up the commit timer for the new transaction. */
-       journal->j_commit_timer.expires = transaction->t_expires;
+       journal->j_commit_timer.expires = round_jiffies(transaction->t_expires);
        add_timer(&journal->j_commit_timer);
 
        J_ASSERT(journal->j_running_transaction == NULL);
index eb550b339bb829c1473f4f84ffd271b9617f954a..38f70ac03becfacda7fff453c58d750f1df4f861 100644 (file)
 /*
  *      file system option (superblock flag)
  */
-/* mount time flag to disable journaling to disk */
-#define JFS_NOINTEGRITY 0x00000010
+
+/* directory option */
+#define JFS_UNICODE    0x00000001      /* unicode name */
 
 /* mount time flags for error handling */
 #define JFS_ERR_REMOUNT_RO 0x00000002   /* remount read-only */
 #define JFS_ERR_CONTINUE   0x00000004   /* continue */
 #define JFS_ERR_PANIC      0x00000008   /* panic */
 
+/* Quota support */
 #define        JFS_USRQUOTA    0x00000010
 #define        JFS_GRPQUOTA    0x00000020
 
-/* platform option (conditional compilation) */
-#define JFS_AIX                0x80000000      /* AIX support */
-/*     POSIX name/directory  support */
-
-#define JFS_OS2                0x40000000      /* OS/2 support */
-/*     case-insensitive name/directory support */
-
-#define JFS_DFS                0x20000000      /* DCE DFS LFS support */
-
-#define JFS_LINUX      0x10000000      /* Linux support */
-/*     case-sensitive name/directory support */
-
-/* directory option */
-#define JFS_UNICODE    0x00000001      /* unicode name */
+/* mount time flag to disable journaling to disk */
+#define JFS_NOINTEGRITY 0x00000040
 
 /* commit option */
 #define        JFS_COMMIT      0x00000f00      /* commit option mask */
@@ -61,6 +51,7 @@
 #define        JFS_LAZYCOMMIT  0x00000200      /* lazy commit */
 #define        JFS_TMPFS       0x00000400      /* temporary file system -
                                         * do not log/commit:
+                                        * Never implemented
                                         */
 
 /* log logical volume option */
 #define JFS_SPARSE     0x00020000      /* sparse regular file */
 
 /* DASD Limits         F226941 */
-#define JFS_DASD_ENABLED       0x00040000      /* DASD limits enabled */
-#define        JFS_DASD_PRIME          0x00080000      /* Prime DASD usage on boot */
+#define JFS_DASD_ENABLED 0x00040000    /* DASD limits enabled */
+#define        JFS_DASD_PRIME  0x00080000      /* Prime DASD usage on boot */
 
 /* big endian flag */
-#define        JFS_SWAP_BYTES          0x00100000      /* running on big endian computer */
+#define        JFS_SWAP_BYTES  0x00100000      /* running on big endian computer */
 
 /* Directory index */
-#define JFS_DIR_INDEX          0x00200000      /* Persistent index for */
-                                               /* directory entries    */
+#define JFS_DIR_INDEX  0x00200000      /* Persistent index for */
 
+/* platform options */
+#define JFS_LINUX      0x10000000      /* Linux support */
+#define JFS_DFS                0x20000000      /* DCE DFS LFS support */
+/*     Never implemented */
+
+#define JFS_OS2                0x40000000      /* OS/2 support */
+/*     case-insensitive name/directory support */
+
+#define JFS_AIX                0x80000000      /* AIX support */
+/*     POSIX name/directory  support - Never implemented*/
 
 /*
  *     buffer cache configuration
index 0d94319e8681b010cb8aaf0bf9c5df77504ddcde..c989fb4cf7b9ce1bfc479ca7a0b6a4881e333c63 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -864,8 +864,7 @@ int get_unused_fd(void)
 
 repeat:
        fdt = files_fdtable(files);
-       fd = find_next_zero_bit(fdt->open_fds->fds_bits,
-                               fdt->max_fdset,
+       fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
                                files->next_fd);
 
        /*
index fd959d5b5a802c0897d586114a0c1fb2878ceec0..77a57b5799c41cfc2fe84b0bdba00d66b8072eec 100644 (file)
@@ -1804,6 +1804,27 @@ static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filld
                                proc_base_instantiate, task, p);
 }
 
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static int proc_pid_io_accounting(struct task_struct *task, char *buffer)
+{
+       return sprintf(buffer,
+                       "rchar: %llu\n"
+                       "wchar: %llu\n"
+                       "syscr: %llu\n"
+                       "syscw: %llu\n"
+                       "read_bytes: %llu\n"
+                       "write_bytes: %llu\n"
+                       "cancelled_write_bytes: %llu\n",
+                       (unsigned long long)task->rchar,
+                       (unsigned long long)task->wchar,
+                       (unsigned long long)task->syscr,
+                       (unsigned long long)task->syscw,
+                       (unsigned long long)task->ioac.read_bytes,
+                       (unsigned long long)task->ioac.write_bytes,
+                       (unsigned long long)task->ioac.cancelled_write_bytes);
+}
+#endif
+
 /*
  * Thread groups
  */
@@ -1855,6 +1876,9 @@ static struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
 #endif
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+       INF("io",       S_IRUGO, pid_io_accounting),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file * filp,
index dc3e580d1dcaa817b59dd1c1955db1ded46bb0e2..92ea7743fe8f59dd97f925b8e7923a463fb5b022 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/vmalloc.h>
 #include <linux/crash_dump.h>
 #include <linux/pid_namespace.h>
+#include <linux/compile.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -253,8 +254,15 @@ static int version_read_proc(char *page, char **start, off_t off,
 {
        int len;
 
-       len = sprintf(page, linux_banner,
-               utsname()->release, utsname()->version);
+       /* FIXED STRING! Don't touch! */
+       len = snprintf(page, PAGE_SIZE,
+               "%s version %s"
+               " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
+               " (" LINUX_COMPILER ")"
+               " %s\n",
+               utsname()->sysname,
+               utsname()->release,
+               utsname()->version);
        return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
index dcbc1112b7ec214c063eaf5786bb17d5f208e6b0..fe0893afd931e02081eca0b968e30a19e7ce2a73 100644 (file)
@@ -311,7 +311,7 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
 {
        fd_set_bits fds;
        void *bits;
-       int ret, max_fdset;
+       int ret, max_fds;
        unsigned int size;
        struct fdtable *fdt;
        /* Allocate small arguments on the stack to save memory and be faster */
@@ -321,13 +321,13 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
        if (n < 0)
                goto out_nofds;
 
-       /* max_fdset can increase, so grab it once to avoid race */
+       /* max_fds can increase, so grab it once to avoid race */
        rcu_read_lock();
        fdt = files_fdtable(current->files);
-       max_fdset = fdt->max_fdset;
+       max_fds = fdt->max_fds;
        rcu_read_unlock();
-       if (n > max_fdset)
-               n = max_fdset;
+       if (n > max_fds)
+               n = max_fds;
 
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
index 8e6b56fc1cad4b52504dd9c4055a3fda3a6d595d..b56eb754e2d23d6f87208a9cff5c9c759193f0d8 100644 (file)
@@ -1406,7 +1406,7 @@ xfs_vm_direct_IO(
                        xfs_end_io_direct);
        }
 
-       if (unlikely(ret <= 0 && iocb->private))
+       if (unlikely(ret != -EIOCBQUEUED && iocb->private))
                xfs_destroy_ioend(iocb->private);
        return ret;
 }
index 915590c391c8c8a4f6f7972912e7ce3cbf247d5c..acc7ec7a84a16614036b88c3e2c42be0c8ee865b 100644 (file)
 #define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00)
 #define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
 #define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
-#define SSP_TIMEOUT_SCALE (2712)
 #elif defined(CONFIG_PXA27x)
 #define CLOCK_SPEED_HZ 13000000
 #define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
 #define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
 #define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
-#define SSP_TIMEOUT_SCALE (769)
 #endif
 
-#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE)
 #define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1)))))
 #define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2)))))
 #define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3)))))
@@ -63,7 +60,7 @@ struct pxa2xx_spi_chip {
        u8 tx_threshold;
        u8 rx_threshold;
        u8 dma_burst_size;
-       u32 timeout_microsecs;
+       u32 timeout;
        u8 enable_loopback;
        void (*cs_control)(u32 command);
 };
diff --git a/include/asm-avr32/arch-at32ap/at32ap7000.h b/include/asm-avr32/arch-at32ap/at32ap7000.h
new file mode 100644 (file)
index 0000000..ba85e04
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Pin definitions for AT32AP7000.
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * 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 __ASM_ARCH_AT32AP7000_H__
+#define __ASM_ARCH_AT32AP7000_H__
+
+#define GPIO_PERIPH_A  0
+#define GPIO_PERIPH_B  1
+
+#define NR_GPIO_CONTROLLERS    4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE (0)
+#define GPIO_PIOB_BASE (GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE (GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE (GPIO_PIOC_BASE + 32)
+
+#define GPIO_PIN_PA(N) (GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N) (GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N) (GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N) (GPIO_PIOD_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP7000_H__ */
index a39b3e999f18dca54774979c4f500b17fe785b3d..b120ee030c867b97a46d1d314fe376d0f5fbd2e7 100644 (file)
@@ -21,10 +21,7 @@ void at32_map_usart(unsigned int hw_id, unsigned int line);
 struct platform_device *at32_add_device_usart(unsigned int id);
 
 struct eth_platform_data {
-       u8      valid;
-       u8      mii_phy_addr;
        u8      is_rmii;
-       u8      hw_addr[6];
 };
 struct platform_device *
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data);
index 4d50421262a1e3948ee1de525bd51e0da75306b6..83c690571322af286ec19d6163691c3402efd792 100644 (file)
@@ -7,10 +7,20 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#ifndef __ASM_AVR32_AT32_PORTMUX_H__
-#define __ASM_AVR32_AT32_PORTMUX_H__
+#ifndef __ASM_ARCH_PORTMUX_H__
+#define __ASM_ARCH_PORTMUX_H__
 
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
-                     unsigned int function_id);
+/*
+ * Set up pin multiplexing, called from board init only.
+ *
+ * The following flags determine the initial state of the pin.
+ */
+#define AT32_GPIOF_PULLUP      0x00000001      /* Enable pull-up */
+#define AT32_GPIOF_OUTPUT      0x00000002      /* Enable output driver */
+#define AT32_GPIOF_HIGH                0x00000004      /* Set output high */
+
+void at32_select_periph(unsigned int pin, unsigned int periph,
+                       unsigned long flags);
+void at32_select_gpio(unsigned int pin, unsigned long flags);
 
-#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */
+#endif /* __ASM_ARCH_PORTMUX_H__ */
index 0580b5d62bba1385073f2b7a7d0218fc78a58f92..5c01e27f0b41d61ac58f3c49e9f2a38aabff1b4c 100644 (file)
@@ -109,7 +109,7 @@ static inline dma_addr_t
 dma_map_single(struct device *dev, void *cpu_addr, size_t size,
               enum dma_data_direction direction)
 {
-       dma_cache_sync(cpu_addr, size, direction);
+       dma_cache_sync(dev, cpu_addr, size, direction);
        return virt_to_bus(cpu_addr);
 }
 
@@ -211,7 +211,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
                sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset;
                virt = page_address(sg[i].page) + sg[i].offset;
-               dma_cache_sync(virt, sg[i].length, direction);
+               dma_cache_sync(dev, virt, sg[i].length, direction);
        }
 
        return nents;
@@ -256,14 +256,14 @@ static inline void
 dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
                        size_t size, enum dma_data_direction direction)
 {
-       dma_cache_sync(bus_to_virt(dma_handle), size, direction);
+       dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
 }
 
 static inline void
 dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
                           size_t size, enum dma_data_direction direction)
 {
-       dma_cache_sync(bus_to_virt(dma_handle), size, direction);
+       dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
 }
 
 /**
@@ -286,7 +286,7 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
        int i;
 
        for (i = 0; i < nents; i++) {
-               dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
                               sg[i].length, direction);
        }
 }
@@ -298,7 +298,7 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
        int i;
 
        for (i = 0; i < nents; i++) {
-               dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
                               sg[i].length, direction);
        }
 }
index 6e9fcebbf89f3ab9cb7a42c74933afe28c3eee72..7437ccaada77fac9f896b683c039bba801f296bb 100644 (file)
        *(.initcall4s.init)                                             \
        *(.initcall5.init)                                              \
        *(.initcall5s.init)                                             \
+       *(.initcallrootfs.init)                                         \
        *(.initcall6.init)                                              \
        *(.initcall6s.init)                                             \
        *(.initcall7.init)                                              \
index 978d09596130d2625d2eee9be4e8b850e8cbf4c5..ac58580ad6647a86d30dd4ae5928c4c1b87a26ca 100644 (file)
@@ -89,6 +89,7 @@ static inline int node_to_first_cpu(int node)
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_EXEC       \
                                | SD_BALANCE_FORK       \
+                               | SD_SERIALIZE          \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index a6e38565ab4c068e6adc16738c7418c7b247b3c9..22ed6749557eaf0bc6d240da6bd8c96647b762e8 100644 (file)
@@ -101,6 +101,7 @@ void build_cpu_to_node_map(void);
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_EXEC       \
                                | SD_BALANCE_FORK       \
+                               | SD_SERIALIZE          \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 64,                   \
index 55a0152feb08c01246b8a58387a1f0eea0826670..432653d7ae09326dafde8ef0b23504ca27b69300 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/types.h>
 #include <asm/page.h>
+#include <asm/ptrace.h>
 
 #define COMPAT_USER_HZ 100
 
index 806213ce31b6cc5447c2f72cec86ec5c73ae49ee..25f0c3f39adf14e0ad7eae21ae03f05477d9af41 100644 (file)
@@ -10,8 +10,6 @@
 #ifndef __ASM_MACH_IP27_IRQ_H
 #define __ASM_MACH_IP27_IRQ_H
 
-#include <asm/sn/arch.h>
-
 /*
  * A hardwired interrupt number is completly stupid for this system - a
  * large configuration might have thousands if not tenthousands of
index a13b715fd9caf5d028af465941d3f6c1f08ff193..44790fdc5d00d989fbf7c5fbd81d007f3119876d 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_MACH_TOPOLOGY_H
 #define _ASM_MACH_TOPOLOGY_H   1
 
-#include <asm/sn/arch.h>
 #include <asm/sn/hub.h>
 #include <asm/mmzone.h>
 
index c4d68bebdca655cc2c1c44f99c4fa0b5b19ca9ea..7f0f120ca07c23b6d42e2bdee1c3081095bf4c07 100644 (file)
@@ -187,4 +187,10 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
 /* Do platform specific device initialization at pci_enable_device() time */
 extern int pcibios_plat_dev_init(struct pci_dev *dev);
 
+/* Chances are this interrupt is wired PC-style ...  */
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+       return channel ? 15 : 14;
+}
+
 #endif /* _ASM_PCI_H */
index 30bf555faeaaee200fec9b2614f9aa17afe76d7b..8a1f2b6f04aca4e4b68fd9b63a2f4a42f7021da0 100644 (file)
@@ -82,6 +82,14 @@ struct pt_regs {
 
 extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
 
+extern NORET_TYPE void die(const char *, struct pt_regs *);
+
+static inline void die_if_kernel(const char *str, struct pt_regs *regs)
+{
+       if (unlikely(!user_mode(regs)))
+               die(str, regs);
+}
+
 #endif
 
 #endif /* _ASM_PTRACE_H */
index 51174af6ac5213608f3f85a0ecc90749adabe421..da523de628be98302df8d306f7ddf3666a6907dd 100644 (file)
@@ -18,7 +18,6 @@
 #endif
 
 typedef u64    hubreg_t;
-typedef u64    nic_t;
 
 #define cputonasid(cpu)                        (cpu_data[(cpu)].p_nasid)
 #define cputoslice(cpu)                        (cpu_data[(cpu)].p_slice)
index 15d70ca561870cb9d48db00c7183b9377df0ee0a..82aeb9e322db9bde8a223a9c4ac30ba05478c308 100644 (file)
@@ -61,6 +61,8 @@
 #endif /* CONFIG_SGI_IP35 */
 #endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */
 
+typedef u64  nic_t;
+
 #define KLCFGINFO_MAGIC        0xbeedbabe
 
 typedef s32 klconf_off_t;
index 9428057a50cfa63b996c7f50fe10bea49bb069bc..5e1289c85ed958f414ec673a535e48b1c056e221 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/barrier.h>
 #include <asm/cpu-features.h>
 #include <asm/dsp.h>
-#include <asm/ptrace.h>
 #include <asm/war.h>
 
 
@@ -336,14 +335,6 @@ extern void *set_except_vector(int n, void *addr);
 extern unsigned long ebase;
 extern void per_cpu_trap_init(void);
 
-extern NORET_TYPE void die(const char *, struct pt_regs *);
-
-static inline void die_if_kernel(const char *str, struct pt_regs *regs)
-{
-       if (unlikely(!user_mode(regs)))
-               die(str, regs);
-}
-
 extern int stop_a_enabled;
 
 /*
index 1e637381c118db47c3694253bf6bfbdb75fe9a92..703970fb0ec0d5d7bdf6b715c2becb7bbf7bd5f3 100644 (file)
@@ -17,7 +17,6 @@ header-y += ipc.h
 header-y += poll.h
 header-y += shmparam.h
 header-y += sockios.h
-header-y += spu_info.h
 header-y += ucontext.h
 header-y += ioctl.h
 header-y += linkage.h
@@ -37,6 +36,7 @@ unifdef-y += posix_types.h
 unifdef-y += ptrace.h
 unifdef-y += seccomp.h
 unifdef-y += signal.h
+unifdef-y += spu_info.h
 unifdef-y += termios.h
 unifdef-y += types.h
 unifdef-y += unistd.h
index 0288144ea024aac5882d92bc47d24af01ee6b706..8f757f6246e4effe36e790c811dd0b7939f4d875 100644 (file)
@@ -209,7 +209,7 @@ int __ilog2_u32(u32 n)
 
 #ifdef __powerpc64__
 static inline __attribute__((const))
-int __ilog2_u64(u32 n)
+int __ilog2_u64(u64 n)
 {
        int bit;
        asm ("cntlzd %0,%1" : "=r" (bit) : "r" (n));
index 978b2c7e84eaf25f9d32a7ffb06c8744ed65fdf4..709568879f731e2367009c778465b639c997775a 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-struct bug_entry {
-       unsigned long   bug_addr;
-       long            line;
-       const char      *file;
-       const char      *function;
-};
-
-struct bug_entry *find_bug(unsigned long bugaddr);
-
-/*
- * If this bit is set in the line number it means that the trap
- * is for WARN_ON rather than BUG or BUG_ON.
- */
-#define BUG_WARNING_TRAP       0x1000000
-
 #ifdef CONFIG_BUG
 
+/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
+   sizeof(struct bug_entry), respectively */
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY                                \
+       ".section __bug_table,\"a\"\n"          \
+       "2:\t" PPC_LONG "1b, %0\n"              \
+       "\t.short %1, %2\n"                     \
+       ".org 2b+%3\n"                          \
+       ".previous\n"
+#else
+#define _EMIT_BUG_ENTRY                                \
+       ".section __bug_table,\"a\"\n"          \
+       "2:\t" PPC_LONG "1b\n"                  \
+       "\t.short %2\n"                         \
+       ".org 2b+%3\n"                          \
+       ".previous\n"
+#endif
+
 /*
  * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
  * optimisations. However depending on the complexity of the condition
  * some compiler versions may not produce optimal results.
  */
 
-#define BUG() do {                                                      \
-       __asm__ __volatile__(                                            \
-               "1:     twi 31,0,0\n"                                    \
-               ".section __bug_table,\"a\"\n"                           \
-               "\t"PPC_LONG"   1b,%0,%1,%2\n"                           \
-               ".previous"                                              \
-               : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
+#define BUG() do {                                             \
+       __asm__ __volatile__(                                   \
+               "1:     twi 31,0,0\n"                           \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                   "i" (0), "i"  (sizeof(struct bug_entry)));  \
+       for(;;) ;                                               \
 } while (0)
 
 #define BUG_ON(x) do {                                         \
@@ -51,23 +54,21 @@ struct bug_entry *find_bug(unsigned long bugaddr);
                        BUG();                                  \
        } else {                                                \
                __asm__ __volatile__(                           \
-               "1:     "PPC_TLNEI"     %0,0\n"                 \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%1,%2,%3\n"                  \
-               ".previous"                                     \
-               : : "r" ((long)(x)), "i" (__LINE__),            \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               "1:     "PPC_TLNEI"     %4,0\n"                 \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__), "i" (0),    \
+                 "i" (sizeof(struct bug_entry)),               \
+                 "r" ((long)(x)));                             \
        }                                                       \
 } while (0)
 
 #define __WARN() do {                                          \
        __asm__ __volatile__(                                   \
                "1:     twi 31,0,0\n"                           \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%0,%1,%2\n"                  \
-               ".previous"                                     \
-               : : "i" (__LINE__ + BUG_WARNING_TRAP),          \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (sizeof(struct bug_entry)));              \
 } while (0)
 
 #define WARN_ON(x) ({                                          \
@@ -77,13 +78,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
                        __WARN();                               \
        } else {                                                \
                __asm__ __volatile__(                           \
-               "1:     "PPC_TLNEI"     %0,0\n"                 \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%1,%2,%3\n"                  \
-               ".previous"                                     \
-               : : "r" (__ret_warn_on),                        \
-                   "i" (__LINE__ + BUG_WARNING_TRAP),          \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               "1:     "PPC_TLNEI"     %4,0\n"                 \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (sizeof(struct bug_entry)),               \
+                 "r" (__ret_warn_on));                         \
        }                                                       \
        unlikely(__ret_warn_on);                                \
 })
index 6fe5c9d4ca3b946e2ad5f348070851b6e039d086..7384b8086b75411e2bc001f60184e344e42b31cf 100644 (file)
@@ -126,6 +126,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTR_NODSISRALIGN           ASM_CONST(0x0000000000100000)
 #define CPU_FTR_PPC_LE                 ASM_CONST(0x0000000000200000)
 #define CPU_FTR_REAL_LE                        ASM_CONST(0x0000000000400000)
+#define CPU_FTR_FPU_UNAVAILABLE                ASM_CONST(0x0000000000800000)
 
 /*
  * Add the 64-bit processor unique features in the top half of the word;
@@ -152,6 +153,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTR_PURR                   LONG_ASM_CONST(0x0000400000000000)
 #define CPU_FTR_CELL_TB_BUG            LONG_ASM_CONST(0x0000800000000000)
 #define CPU_FTR_SPURR                  LONG_ASM_CONST(0x0001000000000000)
+#define CPU_FTR_DSCR                   LONG_ASM_CONST(0x0002000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -295,6 +297,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTRS_E300  (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
            CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
            CPU_FTR_COMMON)
+#define CPU_FTRS_E300C2        (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+           CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+           CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
 #define CPU_FTRS_CLASSIC32     (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
            CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
 #define CPU_FTRS_8XX   (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
@@ -330,13 +335,14 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
-           CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE)
+           CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
+           CPU_FTR_DSCR)
 #define CPU_FTRS_POWER6X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
            CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | \
-           CPU_FTR_SPURR | CPU_FTR_REAL_LE)
+           CPU_FTR_SPURR | CPU_FTR_REAL_LE | CPU_FTR_DSCR)
 #define CPU_FTRS_CELL  (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -364,7 +370,8 @@ enum {
            CPU_FTRS_7450_21 | CPU_FTRS_7450_23 | CPU_FTRS_7455_1 |
            CPU_FTRS_7455_20 | CPU_FTRS_7455 | CPU_FTRS_7447_10 |
            CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX |
-           CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_CLASSIC32 |
+           CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_E300C2 |
+           CPU_FTRS_CLASSIC32 |
 #else
            CPU_FTRS_GENERIC_32 |
 #endif
@@ -403,7 +410,8 @@ enum {
            CPU_FTRS_7450_21 & CPU_FTRS_7450_23 & CPU_FTRS_7455_1 &
            CPU_FTRS_7455_20 & CPU_FTRS_7455 & CPU_FTRS_7447_10 &
            CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX &
-           CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_CLASSIC32 &
+           CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_E300C2 &
+           CPU_FTRS_CLASSIC32 &
 #else
            CPU_FTRS_GENERIC_32 &
 #endif
index fd4a5f5e33d16588ef4c92e7bdbde279901d5e5b..d7a1bc1551c603086c97a2ee1c85f9ad53803172 100644 (file)
@@ -20,8 +20,7 @@
 #ifndef _ASM_POWERPC_DCR_NATIVE_H
 #define _ASM_POWERPC_DCR_NATIVE_H
 #ifdef __KERNEL__
-
-#include <asm/reg.h>
+#ifndef __ASSEMBLY__
 
 typedef struct {} dcr_host_t;
 
@@ -32,7 +31,41 @@ typedef struct {} dcr_host_t;
 #define dcr_read(host, dcr_n)          mfdcr(dcr_n)
 #define dcr_write(host, dcr_n, value)  mtdcr(dcr_n, value)
 
+/* Device Control Registers */
+void __mtdcr(int reg, unsigned int val);
+unsigned int __mfdcr(int reg);
+#define mfdcr(rn)                                              \
+       ({unsigned int rval;                                    \
+       if (__builtin_constant_p(rn))                           \
+               asm volatile("mfdcr %0," __stringify(rn)        \
+                             : "=r" (rval));                   \
+       else                                                    \
+               rval = __mfdcr(rn);                             \
+       rval;})
+
+#define mtdcr(rn, v)                                           \
+do {                                                           \
+       if (__builtin_constant_p(rn))                           \
+               asm volatile("mtdcr " __stringify(rn) ",%0"     \
+                             : : "r" (v));                     \
+       else                                                    \
+               __mtdcr(rn, v);                                 \
+} while (0)
+
+/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
+#define mfdcri(base, reg)                      \
+({                                             \
+       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
+       mfdcr(base ## _CFGDATA);                        \
+})
+
+#define mtdcri(base, reg, data)                        \
+do {                                           \
+       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
+       mtdcr(base ## _CFGDATA, data);          \
+} while (0)
 
+#endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DCR_NATIVE_H */
 
index 473f2c7fd89250c3603cd594f3a4754f9741793a..b66c5e6941f01cabfc128a7b0f4082ac71555fae 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef _ASM_POWERPC_DCR_H
 #define _ASM_POWERPC_DCR_H
 #ifdef __KERNEL__
+#ifdef CONFIG_PPC_DCR
 
 #ifdef CONFIG_PPC_DCR_NATIVE
 #include <asm/dcr-native.h>
@@ -38,5 +39,6 @@ extern unsigned int dcr_resource_len(struct device_node *np,
                                     unsigned int index);
 #endif /* CONFIG_PPC_MERGE */
 
+#endif /* CONFIG_PPC_DCR */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DCR_H */
index d604863d72fb08b9b69a757fe20f117edb8e3cae..9e4dd98eb220ca65a409ffe475bc59a762f84f55 100644 (file)
@@ -107,25 +107,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 
 #endif /* CONFIG_PPC64 */
 
-#define mask_irq(irq)                                          \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->disable)  \
-                       desc->chip->disable(irq);               \
-       })
-#define unmask_irq(irq)                                                \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->enable)   \
-                       desc->chip->enable(irq);                \
-       })
-#define ack_irq(irq)                                           \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->ack)      \
-                       desc->chip->ack(irq);           \
-       })
-
 /*
  * interrupt-retrigger: should we handle this via lost interrupts and IPIs
  * or should we not care like we do now ? --BenH.
index 584fabfb4f08aa9eccfb688727e109da3d021530..e5f14b13ccf0ff2c11ef8392b6697750608ca919 100644 (file)
@@ -46,8 +46,6 @@ struct mod_arch_specific {
        unsigned int num_bugs;
 };
 
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
 /*
  * Select ELF headers.
  * Make empty section for module_frob_arch_sections to expand.
index 7bb7f90098066f81d3ec216141c21294c26ea2ea..cb02c9d1ef938f0c0d8bcdc9169d22236012c543 100644 (file)
@@ -31,12 +31,12 @@ struct pci_controller {
        int last_busno;
 
        void __iomem *io_base_virt;
-       unsigned long io_base_phys;
+       resource_size_t io_base_phys;
 
        /* Some machines have a non 1:1 mapping of
         * the PCI memory space in the CPU bus space
         */
-       unsigned long pci_mem_offset;
+       resource_size_t pci_mem_offset;
        unsigned long pci_io_size;
 
        struct pci_ops *ops;
index 16f13319c7693fbb55cea896bab704885ebd4357..ac656ee6bb193215db3cc9a9c6353726f3963a0e 100644 (file)
@@ -143,8 +143,13 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP  1
 
-#ifdef CONFIG_PPC64
-/* pci_unmap_{single,page} is not a nop, thus... */
+#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
+/*
+ * For 64-bit kernels, pci_unmap_{single,page} is not a nop.
+ * For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and
+ * so on are not nops.
+ * and thus...
+ */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
        dma_addr_t ADDR_NAME;
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
@@ -158,6 +163,20 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
        (((PTR)->LEN_NAME) = (VAL))
 
+#else /* 32-bit && coherent */
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)           (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+
+#endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */
+
+#ifdef CONFIG_PPC64
+
 /* The PCI address space does not equal the physical memory address
  * space (we have an IOMMU).  The IDE and SCSI device layers use
  * this boolean for bounce buffer decisions.
@@ -172,16 +191,8 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
 #endif /* CONFIG_PPC64 */
-       
+
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
                        struct pci_bus_region *region,
                        struct resource *res);
index 6faae7b14d5540f0e5cdcd13b3a31c195d7d980b..a3631b15754ca39bfd49984d631635e56b8f8cf2 100644 (file)
 
 /* Special Purpose Registers (SPRNs)*/
 #define SPRN_CTR       0x009   /* Count Register */
+#define SPRN_DSCR      0x11
 #define SPRN_CTRLF     0x088
 #define SPRN_CTRLT     0x098
 #define   CTRL_CT      0xc0000000      /* current thread */
 #define SPRN_TBRU      0x10D   /* Time Base Read Upper Register (user, R/O) */
 #define SPRN_TBWL      0x11C   /* Time Base Lower Register (super, R/W) */
 #define SPRN_TBWU      0x11D   /* Time Base Upper Register (super, R/W) */
+#define SPRN_SPURR     0x134   /* Scaled PURR */
 #define SPRN_HIOR      0x137   /* 970 Hypervisor interrupt offset */
 #define SPRN_DBAT0L    0x219   /* Data BAT 0 Lower Register */
 #define SPRN_DBAT0U    0x218   /* Data BAT 0 Upper Register */
index 5a0c136c04168f94e8d235a6308702c4cf712c5e..8eaa7b28d9d07d59ad6d2f0a6cb83187380ec8b3 100644 (file)
@@ -159,6 +159,7 @@ extern struct rtas_t rtas;
 
 extern void enter_rtas(unsigned long);
 extern int rtas_token(const char *service);
+extern int rtas_service_present(const char *service);
 extern int rtas_call(int token, int, int, int *, ...);
 extern void rtas_restart(char *cmd);
 extern void rtas_power_off(void);
@@ -221,8 +222,6 @@ extern int rtas_get_error_log_max(void);
 extern spinlock_t rtas_data_buf_lock;
 extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
 
-extern void rtas_stop_self(void);
-
 /* RMO buffer reserved for user-space RTAS use */
 extern unsigned long rtas_rmo_buf;
 
index 50c014007de754c3019fa7f838160a515b6f38f1..6610495f5f166201f5d0e6f3f4ed1b2b665f933c 100644 (file)
@@ -66,6 +66,7 @@ static inline int pcibus_to_node(struct pci_bus *bus)
                                | SD_BALANCE_EXEC       \
                                | SD_BALANCE_NEWIDLE    \
                                | SD_WAKE_IDLE          \
+                               | SD_SERIALIZE          \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
index 6c955d0c1ef0d217199f30ea358dd1f03cf45e31..4d35b844bc58e8fd7e110bc3e620b65e691bf631 100644 (file)
@@ -20,8 +20,8 @@ extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
 extern struct pci_controller* pcibios_alloc_controller(void);
 
 /* Helper function for setting up resources */
-extern void pci_init_resource(struct resource *res, unsigned long start,
-                             unsigned long end, int flags, char *name);
+extern void pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name);
 
 /* Get the PCI host controller for a bus */
 extern struct pci_controller* pci_bus_to_hose(int bus);
@@ -50,12 +50,12 @@ struct pci_controller {
        int bus_offset;
 
        void __iomem *io_base_virt;
-       unsigned long io_base_phys;
+       resource_size_t io_base_phys;
 
        /* Some machines (PReP) have a non 1:1 mapping of
         * the PCI memory space in the CPU bus space
         */
-       unsigned long pci_mem_offset;
+       resource_size_t pci_mem_offset;
 
        struct pci_ops *ops;
        volatile unsigned int __iomem *cfg_addr;
index 11ffaaa5da165abe9adec4d586eba35864fa71dc..9d162028dab92809d4d6b49bc9fce254ccc3932b 100644 (file)
@@ -61,6 +61,27 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
+#ifdef CONFIG_NOT_COHERENT_CACHE
+/*
+ * pci_unmap_{page,single} are NOPs but pci_dma_sync_single_for_cpu()
+ * and so on are not, so...
+ */
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
+       dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
+       __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)                 \
+       ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
+       (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)                   \
+       ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
+       (((PTR)->LEN_NAME) = (VAL))
+
+#else /* coherent */
+
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -69,6 +90,8 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
+#endif /* CONFIG_NOT_COHERENT_CACHE */
+
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index 602fbadeaf480cff1769496e9e37e3796356e7fa..a263fc1e65c41c6990cfc3f0a3ff93629c557778 100644 (file)
@@ -9,41 +9,9 @@
 #ifndef __ASM_PPC_REG_BOOKE_H__
 #define __ASM_PPC_REG_BOOKE_H__
 
-#ifndef __ASSEMBLY__
-/* Device Control Registers */
-void __mtdcr(int reg, unsigned int val);
-unsigned int __mfdcr(int reg);
-#define mfdcr(rn)                                              \
-       ({unsigned int rval;                                    \
-       if (__builtin_constant_p(rn))                           \
-               asm volatile("mfdcr %0," __stringify(rn)        \
-                             : "=r" (rval));                   \
-       else                                                    \
-               rval = __mfdcr(rn);                             \
-       rval;})
-
-#define mtdcr(rn, v)                                           \
-do {                                                           \
-       if (__builtin_constant_p(rn))                           \
-               asm volatile("mtdcr " __stringify(rn) ",%0"     \
-                             : : "r" (v));                     \
-       else                                                    \
-               __mtdcr(rn, v);                                 \
-} while (0)
-
-/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
-#define mfdcri(base, reg)                      \
-({                                             \
-       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
-       mfdcr(base ## _CFGDATA);                        \
-})
-
-#define mtdcri(base, reg, data)                        \
-do {                                           \
-       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
-       mtdcr(base ## _CFGDATA, data);          \
-} while (0)
+#include <asm/dcr.h>
 
+#ifndef __ASSEMBLY__
 /* Performance Monitor Registers */
 #define mfpmr(rn)      ({unsigned int rval; \
                        asm volatile("mfpmr %0," __stringify(rn) \
diff --git a/include/asm-sh/atomic-irq.h b/include/asm-sh/atomic-irq.h
new file mode 100644 (file)
index 0000000..74f7943
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __ASM_SH_ATOMIC_IRQ_H
+#define __ASM_SH_ATOMIC_IRQ_H
+
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * forward to code at the end of this object's .text section, then
+ * branch back to restart the operation.
+ */
+static inline void atomic_add(int i, atomic_t *v)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *(long *)v += i;
+       local_irq_restore(flags);
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *(long *)v -= i;
+       local_irq_restore(flags);
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       unsigned long temp, flags;
+
+       local_irq_save(flags);
+       temp = *(long *)v;
+       temp += i;
+       *(long *)v = temp;
+       local_irq_restore(flags);
+
+       return temp;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+       unsigned long temp, flags;
+
+       local_irq_save(flags);
+       temp = *(long *)v;
+       temp -= i;
+       *(long *)v = temp;
+       local_irq_restore(flags);
+
+       return temp;
+}
+
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *(long *)v &= ~mask;
+       local_irq_restore(flags);
+}
+
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *(long *)v |= mask;
+       local_irq_restore(flags);
+}
+
+#endif /* __ASM_SH_ATOMIC_IRQ_H */
diff --git a/include/asm-sh/atomic-llsc.h b/include/asm-sh/atomic-llsc.h
new file mode 100644 (file)
index 0000000..4b00b78
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __ASM_SH_ATOMIC_LLSC_H
+#define __ASM_SH_ATOMIC_LLSC_H
+
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * forward to code at the end of this object's .text section, then
+ * branch back to restart the operation.
+ */
+static inline void atomic_add(int i, atomic_t *v)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_add    \n"
+"      add     %1, %0                          \n"
+"      movco.l %0, @%2                         \n"
+"      bf      1b                              \n"
+       : "=&z" (tmp)
+       : "r" (i), "r" (&v->counter)
+       : "t");
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_sub    \n"
+"      sub     %1, %0                          \n"
+"      movco.l %0, @%2                         \n"
+"      bf      1b                              \n"
+       : "=&z" (tmp)
+       : "r" (i), "r" (&v->counter)
+       : "t");
+}
+
+/*
+ * SH-4A note:
+ *
+ * We basically get atomic_xxx_return() for free compared with
+ * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
+ * encoding, so the retval is automatically set without having to
+ * do any special work.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       unsigned long temp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_add_return     \n"
+"      add     %1, %0                                  \n"
+"      movco.l %0, @%2                                 \n"
+"      bf      1b                                      \n"
+"      synco                                           \n"
+       : "=&z" (temp)
+       : "r" (i), "r" (&v->counter)
+       : "t");
+
+       return temp;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+       unsigned long temp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_sub_return     \n"
+"      sub     %1, %0                                  \n"
+"      movco.l %0, @%2                                 \n"
+"      bf      1b                                      \n"
+"      synco                                           \n"
+       : "=&z" (temp)
+       : "r" (i), "r" (&v->counter)
+       : "t");
+
+       return temp;
+}
+
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_clear_mask     \n"
+"      and     %1, %0                                  \n"
+"      movco.l %0, @%2                                 \n"
+"      bf      1b                                      \n"
+       : "=&z" (tmp)
+       : "r" (~mask), "r" (&v->counter)
+       : "t");
+}
+
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+"1:    movli.l @%2, %0         ! atomic_set_mask       \n"
+"      or      %1, %0                                  \n"
+"      movco.l %0, @%2                                 \n"
+"      bf      1b                                      \n"
+       : "=&z" (tmp)
+       : "r" (mask), "r" (&v->counter)
+       : "t");
+}
+
+#endif /* __ASM_SH_ATOMIC_LLSC_H */
index 28305c3cbddf88d770f7c22020bec367121e74a2..e12570b9339dcb1a127222cdc04383752a88fc59 100644 (file)
@@ -17,119 +17,14 @@ typedef struct { volatile int counter; } atomic_t;
 #include <linux/compiler.h>
 #include <asm/system.h>
 
-/*
- * To get proper branch prediction for the main line, we must branch
- * forward to code at the end of this object's .text section, then
- * branch back to restart the operation.
- */
-static inline void atomic_add(int i, atomic_t *v)
-{
 #ifdef CONFIG_CPU_SH4A
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_add    \n"
-"      add     %1, %0                          \n"
-"      movco.l %0, @%2                         \n"
-"      bf      1b                              \n"
-       : "=&z" (tmp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
+#include <asm/atomic-llsc.h>
 #else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       *(long *)v += i;
-       local_irq_restore(flags);
-#endif
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-#ifdef CONFIG_CPU_SH4A
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_sub    \n"
-"      sub     %1, %0                          \n"
-"      movco.l %0, @%2                         \n"
-"      bf      1b                              \n"
-       : "=&z" (tmp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
-#else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       *(long *)v -= i;
-       local_irq_restore(flags);
+#include <asm/atomic-irq.h>
 #endif
-}
-
-/*
- * SH-4A note:
- *
- * We basically get atomic_xxx_return() for free compared with
- * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
- * encoding, so the retval is automatically set without having to
- * do any special work.
- */
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-       unsigned long temp;
-
-#ifdef CONFIG_CPU_SH4A
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_add_return     \n"
-"      add     %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-"      synco                                           \n"
-       : "=&z" (temp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
-#else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       temp = *(long *)v;
-       temp += i;
-       *(long *)v = temp;
-       local_irq_restore(flags);
-#endif
-
-       return temp;
-}
 
 #define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
 
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-       unsigned long temp;
-
-#ifdef CONFIG_CPU_SH4A
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_sub_return     \n"
-"      sub     %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-"      synco                                           \n"
-       : "=&z" (temp)
-       : "r" (i), "r" (&v->counter)
-       : "t");
-#else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       temp = *(long *)v;
-       temp -= i;
-       *(long *)v = temp;
-       local_irq_restore(flags);
-#endif
-
-       return temp;
-}
-
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
 #define atomic_inc_return(v) atomic_add_return(1,(v))
 
@@ -180,50 +75,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 }
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
-static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
-{
-#ifdef CONFIG_CPU_SH4A
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_clear_mask     \n"
-"      and     %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-       : "=&z" (tmp)
-       : "r" (~mask), "r" (&v->counter)
-       : "t");
-#else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       *(long *)v &= ~mask;
-       local_irq_restore(flags);
-#endif
-}
-
-static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
-{
-#ifdef CONFIG_CPU_SH4A
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-"1:    movli.l @%2, %0         ! atomic_set_mask       \n"
-"      or      %1, %0                                  \n"
-"      movco.l %0, @%2                                 \n"
-"      bf      1b                                      \n"
-       : "=&z" (tmp)
-       : "r" (mask), "r" (&v->counter)
-       : "t");
-#else
-       unsigned long flags;
-
-       local_irq_save(flags);
-       *(long *)v |= mask;
-       local_irq_restore(flags);
-#endif
-}
-
 /* Atomic operations are already serializing on SH */
 #define smp_mb__before_atomic_dec()    barrier()
 #define smp_mb__after_atomic_dec()     barrier()
index 1b4fc52a59e86beb62adf210158260c453a01ab5..2f89dd06d0cdbb140adf5d518e895af28a971e7f 100644 (file)
@@ -1,19 +1,54 @@
 #ifndef __ASM_SH_BUG_H
 #define __ASM_SH_BUG_H
 
-
 #ifdef CONFIG_BUG
-/*
- * Tell the user there is some problem.
- */
-#define BUG() do { \
-       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-       *(volatile int *)0 = 0; \
+
+struct bug_frame {
+       unsigned short  opcode;
+       unsigned short  line;
+       const char      *file;
+       const char      *func;
+};
+
+struct pt_regs;
+
+extern void handle_BUG(struct pt_regs *);
+
+#define TRAPA_BUG_OPCODE       0xc33e  /* trapa #0x3e */
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define BUG()                                          \
+do {                                                   \
+       __asm__ __volatile__ (                          \
+               ".align 2\n\t"                          \
+               ".short %O0\n\t"                        \
+               ".short %O1\n\t"                        \
+               ".long  %O2\n\t"                        \
+               ".long  %O3\n\t"                        \
+               :                                       \
+               : "n" (TRAPA_BUG_OPCODE),               \
+                 "i" (__LINE__), "X" (__FILE__),       \
+                 "X" (__FUNCTION__));                  \
+} while (0)
+
+#else
+
+#define BUG()                                  \
+do {                                           \
+       __asm__ __volatile__ (                  \
+               ".align 2\n\t"                  \
+               ".short %O0\n\t"                \
+               :                               \
+               : "n" (TRAPA_BUG_OPCODE));      \
 } while (0)
 
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
 #define HAVE_ARCH_BUG
-#endif
+
+#endif /* CONFIG_BUG */
 
 #include <asm-generic/bug.h>
 
-#endif
+#endif /* __ASM_SH_BUG_H */
index 795047da5e17e28cc0f433209a4d5afc48284ca2..a294997a84127b02e42174dcb670e17629ab1392 100644 (file)
@@ -16,9 +16,8 @@
 
 static void __init check_bugs(void)
 {
-       extern char *get_cpu_subtype(void);
        extern unsigned long loops_per_jiffy;
-       char *p= &init_utsname()->machine[2]; /* "sh" */
+       char *p = &init_utsname()->machine[2]; /* "sh" */
 
        cpu_data->loops_per_jiffy = loops_per_jiffy;
 
@@ -40,6 +39,15 @@ static void __init check_bugs(void)
                *p++ = '4';
                *p++ = 'a';
                break;
+       case CPU_SH73180 ... CPU_SH7722:
+               *p++ = '4';
+               *p++ = 'a';
+               *p++ = 'l';
+               *p++ = '-';
+               *p++ = 'd';
+               *p++ = 's';
+               *p++ = 'p';
+               break;
        default:
                *p++ = '?';
                *p++ = '!';
index d44344c88e73b69c07d4d6417206f36dd1aea503..4bc8357e8892c65e8cf586de88fee3d3ef9acc78 100644 (file)
@@ -34,25 +34,26 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  */
 
 asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
-                                         int len, __wsum sum, int *src_err_ptr, int *dst_err_ptr);
+                                           int len, __wsum sum,
+                                           int *src_err_ptr, int *dst_err_ptr);
 
 /*
  *     Note: when you get a NULL pointer exception here this means someone
- *     passed in an incorrect kernel address to one of these functions. 
- *     
- *     If you use these functions directly please don't forget the 
+ *     passed in an incorrect kernel address to one of these functions.
+ *
+ *     If you use these functions directly please don't forget the
  *     access_ok().
  */
-static __inline__
+static inline
 __wsum csum_partial_copy_nocheck(const void *src, void *dst,
-                                       int len, __wsum sum)
+                                int len, __wsum sum)
 {
-       return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+       return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL);
 }
 
-static __inline__
+static inline
 __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
-                                               int len, __wsum sum, int *err_ptr)
+                                  int len, __wsum sum, int *err_ptr)
 {
        return csum_partial_copy_generic((__force const void *)src, dst,
                                        len, sum, err_ptr, NULL);
@@ -62,7 +63,7 @@ __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
  *     Fold a partial checksum
  */
 
-static __inline__ __sum16 csum_fold(__wsum sum)
+static inline __sum16 csum_fold(__wsum sum)
 {
        unsigned int __dummy;
        __asm__("swap.w %0, %1\n\t"
@@ -85,7 +86,7 @@ static __inline__ __sum16 csum_fold(__wsum sum)
  *      i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted
  *      for linux by * Arnt Gulbrandsen.
  */
-static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
        unsigned int sum, __dummy0, __dummy1;
 
@@ -113,10 +114,10 @@ static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
        return  csum_fold(sum);
 }
 
-static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
-                                                  unsigned short len,
-                                                  unsigned short proto,
-                                                  __wsum sum)
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+                                       unsigned short len,
+                                       unsigned short proto,
+                                       __wsum sum)
 {
 #ifdef __LITTLE_ENDIAN__
        unsigned long len_proto = (proto + len) << 8;
@@ -132,6 +133,7 @@ static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
                : "=r" (sum), "=r" (len_proto)
                : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)
                : "t");
+
        return sum;
 }
 
@@ -139,30 +141,28 @@ static __inline__ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
  * computes the checksum of the TCP/UDP pseudo-header
  * returns a 16-bit checksum, already complemented
  */
-static __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
-                                                      unsigned short len,
-                                                      unsigned short proto,
-                                                      __wsum sum)
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+                                       unsigned short len,
+                                       unsigned short proto,
+                                       __wsum sum)
 {
-       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+       return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
 }
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
-
-static __inline__ __sum16 ip_compute_csum(const void *buff, int len)
+static inline __sum16 ip_compute_csum(const void *buff, int len)
 {
-    return csum_fold (csum_partial(buff, len, 0));
+    return csum_fold(csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
-#ifdef CONFIG_IPV6
-static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
-                                         const struct in6_addr *daddr,
-                                         __u32 len, unsigned short proto,
-                                         __wsum sum)
+static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                                     const struct in6_addr *daddr,
+                                     __u32 len, unsigned short proto,
+                                     __wsum sum)
 {
        unsigned int __dummy;
        __asm__("clrt\n\t"
@@ -187,22 +187,21 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
                "movt   %1\n\t"
                "add    %1, %0\n"
                : "=r" (sum), "=&r" (__dummy)
-               : "r" (saddr), "r" (daddr), 
+               : "r" (saddr), "r" (daddr),
                  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
                : "t");
 
        return csum_fold(sum);
 }
-#endif
 
-/* 
+/*
  *     Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user (const void *src,
-                                                     void __user *dst,
-                                                     int len, __wsum sum,
-                                                     int *err_ptr)
+static inline __wsum csum_and_copy_to_user(const void *src,
+                                          void __user *dst,
+                                          int len, __wsum sum,
+                                          int *err_ptr)
 {
        if (access_ok(VERIFY_WRITE, dst, len))
                return csum_partial_copy_generic((__force const void *)src,
index 6e9c7e6ee8e4e025d749ad1dbbce65a2cdb76198..f92b20a0983d7e6001cb5e8a548a09e8966fbddb 100644 (file)
@@ -22,7 +22,7 @@
 #define CCR_CACHE_ICE  0x0100  /* Instruction Cache Enable */
 #define CCR_CACHE_ICI  0x0800  /* IC Invalidate */
 #define CCR_CACHE_IIX  0x8000  /* IC Index Enable */
-#ifndef CONFIG_CPU_SUBTYPE_SH7780
+#ifndef CONFIG_CPU_SH4A
 #define CCR_CACHE_EMODE        0x80000000      /* EMODE Enable */
 #endif
 
index ef2b9b1ae41f591a535287e17a525359be2a4628..602d061ca2dc6e11988d750cb1e0ccb5a0da0775 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef __ASM_CPU_SH4_FREQ_H
 #define __ASM_CPU_SH4_FREQ_H
 
-#if defined(CONFIG_CPU_SUBTYPE_SH73180)
+#if defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7722)
 #define FRQCR                  0xa4150000
 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
 #define        FRQCR                   0xffc80000
index 37ab0c131a4d9913036ab1997db036877bec3fda..8d0867b98e05141ce77d5bb4f3837e3877e0c124 100644 (file)
@@ -67,7 +67,7 @@ static inline dma_addr_t dma_map_single(struct device *dev,
        if (dev->bus == &pci_bus_type)
                return virt_to_bus(ptr);
 #endif
-       dma_cache_sync(ptr, size, dir);
+       dma_cache_sync(dev, ptr, size, dir);
 
        return virt_to_bus(ptr);
 }
@@ -81,7 +81,7 @@ static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nents; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
                               sg[i].length, dir);
 #endif
                sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
@@ -112,7 +112,7 @@ static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
        if (dev->bus == &pci_bus_type)
                return;
 #endif
-       dma_cache_sync(bus_to_virt(dma_handle), size, dir);
+       dma_cache_sync(dev, bus_to_virt(dma_handle), size, dir);
 }
 
 static inline void dma_sync_single_range(struct device *dev,
@@ -124,7 +124,7 @@ static inline void dma_sync_single_range(struct device *dev,
        if (dev->bus == &pci_bus_type)
                return;
 #endif
-       dma_cache_sync(bus_to_virt(dma_handle) + offset, size, dir);
+       dma_cache_sync(dev, bus_to_virt(dma_handle) + offset, size, dir);
 }
 
 static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
@@ -134,7 +134,7 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
 
        for (i = 0; i < nelems; i++) {
 #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-               dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+               dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset,
                               sg[i].length, dir);
 #endif
                sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
index fd576088e47edd0085ba8aa1f702a3c1b44dffd0..bff965ef4b95201626d5056e26f4e00c97975292 100644 (file)
@@ -37,7 +37,8 @@
 # define ONCHIP_NR_IRQS 144
 #elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
       defined(CONFIG_CPU_SUBTYPE_SH73180) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7343)
+      defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7722)
 # define ONCHIP_NR_IRQS 109
 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
 # define ONCHIP_NR_IRQS 111
@@ -79,6 +80,8 @@
 # define OFFCHIP_NR_IRQS 16
 #elif defined(CONFIG_SH_7343_SOLUTION_ENGINE)
 # define OFFCHIP_NR_IRQS 12
+#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+# define OFFCHIP_NR_IRQS 14
 #elif defined(CONFIG_SH_UNKNOWN)
 # define OFFCHIP_NR_IRQS 16    /* Must also be last */
 #else
index c84901dbd8e51cf2097e591c6c439c232443d611..036ca28438661f781aa9d84af95652e9bd1de1c9 100644 (file)
@@ -508,16 +508,50 @@ struct vm_area_struct;
 extern void update_mmu_cache(struct vm_area_struct * vma,
                             unsigned long address, pte_t pte);
 
-/* Encode and de-code a swap entry */
 /*
+ * Encode and de-code a swap entry
+ *
+ * Constraints:
+ *     _PAGE_FILE at bit 0
+ *     _PAGE_PRESENT at bit 8
+ *     _PAGE_PROTNONE at bit 9
+ *
+ * For the normal case, we encode the swap type into bits 0:7 and the
+ * swap offset into bits 10:30. For the 64-bit PTE case, we keep the
+ * preserved bits in the low 32-bits and use the upper 32 as the swap
+ * offset (along with a 5-bit type), following the same approach as x86
+ * PAE. This keeps the logic quite simple, and allows for a full 32
+ * PTE_FILE_MAX_BITS, as opposed to the 29-bits we're constrained with
+ * in the pte_low case.
+ *
+ * As is evident by the Alpha code, if we ever get a 64-bit unsigned
+ * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes
+ * much cleaner..
+ *
  * NOTE: We should set ZEROs at the position of _PAGE_PRESENT
  *       and _PAGE_PROTNONE bits
  */
-#define __swp_type(x)          ((x).val & 0xff)
-#define __swp_offset(x)                ((x).val >> 10)
-#define __swp_entry(type, offset) ((swp_entry_t) { (type) | ((offset) << 10) })
-#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) >> 1 })
-#define __swp_entry_to_pte(x)  ((pte_t) { (x).val << 1 })
+#ifdef CONFIG_X2TLB
+#define __swp_type(x)                  ((x).val & 0x1f)
+#define __swp_offset(x)                        ((x).val >> 5)
+#define __swp_entry(type, offset)      ((swp_entry_t){ (type) | (offset) << 5})
+#define __pte_to_swp_entry(pte)                ((swp_entry_t){ (pte).pte_high })
+#define __swp_entry_to_pte(x)          ((pte_t){ 0, (x).val })
+
+/*
+ * Encode and decode a nonlinear file mapping entry
+ */
+#define pte_to_pgoff(pte)              ((pte).pte_high)
+#define pgoff_to_pte(off)              ((pte_t) { _PAGE_FILE, (off) })
+
+#define PTE_FILE_MAX_BITS              32
+#else
+#define __swp_type(x)                  ((x).val & 0xff)
+#define __swp_offset(x)                        ((x).val >> 10)
+#define __swp_entry(type, offset)      ((swp_entry_t){(type) | (offset) <<10})
+
+#define __pte_to_swp_entry(pte)                ((swp_entry_t) { pte_val(pte) >> 1 })
+#define __swp_entry_to_pte(x)          ((pte_t) { (x).val << 1 })
 
 /*
  * Encode and decode a nonlinear file mapping entry
@@ -525,6 +559,7 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
 #define PTE_FILE_MAX_BITS      29
 #define pte_to_pgoff(pte)      (pte_val(pte) >> 1)
 #define pgoff_to_pte(off)      ((pte_t) { ((off) << 1) | _PAGE_FILE })
+#endif
 
 typedef pte_t *pte_addr_t;
 
index 6f1dd7ca1b1d68515bab5f3ebaa08efd1275fbd5..e29f2abb92defc7f9d24a6d8d4f0b3a9be7d365e 100644 (file)
@@ -27,6 +27,8 @@
 #define CCN_CVR                0xff000040
 #define CCN_PRR                0xff000044
 
+const char *get_cpu_subtype(void);
+
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
  *
@@ -52,8 +54,10 @@ enum cpu_type {
        CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501,
 
        /* SH-4A types */
-       CPU_SH73180, CPU_SH7343, CPU_SH7770, CPU_SH7780, CPU_SH7781,
-       CPU_SH7785,
+       CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785,
+
+       /* SH4AL-DSP types */
+       CPU_SH73180, CPU_SH7343, CPU_SH7722,
 
        /* Unknown subtype */
        CPU_SH_NONE
index dfc6bad567f050c848f6b8cded7d0436c8702264..4903f9e52dd858aee3a5805da7d22a156798d98f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 
 struct push_switch {
        /* switch state */
@@ -12,6 +13,8 @@ struct push_switch {
        struct timer_list       debounce;
        /* workqueue */
        struct work_struct      work;
+       /* platform device, for workqueue handler */
+       struct platform_device  *pdev;
 };
 
 struct push_switch_platform_info {
index 27f65972b3bbd89a565b123576f5084dab2f71e5..93e5a062df880ee991c332edca71a532eb2341cb 100644 (file)
@@ -152,9 +152,9 @@ extern void dvma_init(struct sbus_bus *);
 #define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
 
 /* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  (((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    (((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs)  (((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
+#define DMA_ERROR_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs)    ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+#define DMA_WRITE_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
 #define DMA_OFF(__regs)                \
 do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
        tmp &= ~DMA_ENABLE; \
diff --git a/include/asm-sparc64/irqflags.h b/include/asm-sparc64/irqflags.h
new file mode 100644 (file)
index 0000000..024fc54
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * include/asm-sparc64/irqflags.h
+ *
+ * IRQ flags handling
+ *
+ * This file gets included from lowlevel asm headers too, to provide
+ * wrapped versions of the local_irq_*() APIs, based on the
+ * raw_local_irq_*() functions from the lowlevel headers.
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+static inline unsigned long __raw_local_save_flags(void)
+{
+       unsigned long flags;
+
+       __asm__ __volatile__(
+               "rdpr   %%pil, %0"
+               : "=r" (flags)
+       );
+
+       return flags;
+}
+
+#define raw_local_save_flags(flags) \
+               do { (flags) = __raw_local_save_flags(); } while (0)
+
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+       __asm__ __volatile__(
+               "wrpr   %0, %%pil"
+               : /* no output */
+               : "r" (flags)
+               : "memory"
+       );
+}
+
+static inline void raw_local_irq_disable(void)
+{
+       __asm__ __volatile__(
+               "wrpr   15, %%pil"
+               : /* no outputs */
+               : /* no inputs */
+               : "memory"
+       );
+}
+
+static inline void raw_local_irq_enable(void)
+{
+       __asm__ __volatile__(
+               "wrpr   0, %%pil"
+               : /* no outputs */
+               : /* no inputs */
+               : "memory"
+       );
+}
+
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags > 0);
+}
+
+static inline int raw_irqs_disabled(void)
+{
+       unsigned long flags = __raw_local_save_flags();
+
+       return raw_irqs_disabled_flags(flags);
+}
+
+/*
+ * For spinlocks, etc:
+ */
+static inline unsigned long __raw_local_irq_save(void)
+{
+       unsigned long flags = __raw_local_save_flags();
+
+       raw_local_irq_disable();
+
+       return flags;
+}
+
+#define raw_local_irq_save(flags) \
+               do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif /* (__ASSEMBLY__) */
+
+#endif /* !(_ASM_IRQFLAGS_H) */
index c9f5c34d318c92c0bf4f3f8d8d5f329526b44af3..becc38fa06c5a5c60422c4f4d62efcb1ab4494ce 100644 (file)
@@ -13,7 +13,11 @@ typedef u32 kprobe_opcode_t;
 #define JPROBE_ENTRY(pentry)   (kprobe_opcode_t *)pentry
 #define arch_remove_kprobe(p)  do {} while (0)
 #define  ARCH_INACTIVE_KPROBE_COUNT 0
-#define flush_insn_slot(p)     do { } while (0)
+
+#define flush_insn_slot(p)             \
+do {   flushi(&(p)->ainsn.insn[0]);    \
+       flushi(&(p)->ainsn.insn[1]);    \
+} while (0)
 
 /* Architecture specific copy of original instruction*/
 struct arch_specific_insn {
@@ -23,7 +27,7 @@ struct arch_specific_insn {
 
 struct prev_kprobe {
        struct kprobe *kp;
-       unsigned int status;
+       unsigned long status;
        unsigned long orig_tnpc;
        unsigned long orig_tstate_pil;
 };
@@ -33,10 +37,7 @@ struct kprobe_ctlblk {
        unsigned long kprobe_status;
        unsigned long kprobe_orig_tnpc;
        unsigned long kprobe_orig_tstate_pil;
-       long *jprobe_saved_esp;
        struct pt_regs jprobe_saved_regs;
-       struct pt_regs *jprobe_saved_regs_location;
-       struct sparc_stackf jprobe_saved_stack;
        struct prev_kprobe prev_kprobe;
 };
 
index cef5e8270421beda324419c8210b4ffa3a7e294d..1294b7ce5d06c0987870424ddfceacc87ed42b08 100644 (file)
@@ -23,20 +23,33 @@ struct rw_semaphore {
        signed int count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map      dep_map;
+#endif
 };
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
+  __RWSEM_DEP_MAP_INIT(name) }
 
 #define DECLARE_RWSEM(name) \
        struct rw_semaphore name = __RWSEM_INITIALIZER(name)
 
-static __inline__ void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+                        struct lock_class_key *key);
+
+#define init_rwsem(sem)                                                \
+do {                                                           \
+       static struct lock_class_key __key;                     \
+                                                               \
+       __init_rwsem((sem), #sem, &__key);                      \
+} while (0)
 
 extern void __down_read(struct rw_semaphore *sem);
 extern int __down_read_trylock(struct rw_semaphore *sem);
@@ -46,6 +59,11 @@ extern void __up_read(struct rw_semaphore *sem);
 extern void __up_write(struct rw_semaphore *sem);
 extern void __downgrade_write(struct rw_semaphore *sem);
 
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+{
+       __down_write(sem);
+}
+
 static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
 {
        return atomic_add_return(delta, (atomic_t *)(&sem->count));
index a8b7432c9a70825f3b7d0c6e3b02f3772c24673c..32281acb878b3dc82745266ea1c5b6fd1dd87e17 100644 (file)
@@ -7,6 +7,9 @@
 #include <asm/visasm.h>
 
 #ifndef __ASSEMBLY__
+
+#include <linux/irqflags.h>
+
 /*
  * Sparc (general) CPU types
  */
@@ -72,52 +75,6 @@ do { __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 
 #endif
 
-#define setipl(__new_ipl) \
-       __asm__ __volatile__("wrpr      %0, %%pil"  : : "r" (__new_ipl) : "memory")
-
-#define local_irq_disable() \
-       __asm__ __volatile__("wrpr      15, %%pil" : : : "memory")
-
-#define local_irq_enable() \
-       __asm__ __volatile__("wrpr      0, %%pil" : : : "memory")
-
-#define getipl() \
-({ unsigned long retval; __asm__ __volatile__("rdpr    %%pil, %0" : "=r" (retval)); retval; })
-
-#define swap_pil(__new_pil) \
-({     unsigned long retval; \
-       __asm__ __volatile__("rdpr      %%pil, %0\n\t" \
-                            "wrpr      %1, %%pil" \
-                            : "=&r" (retval) \
-                            : "r" (__new_pil) \
-                            : "memory"); \
-       retval; \
-})
-
-#define read_pil_and_cli() \
-({     unsigned long retval; \
-       __asm__ __volatile__("rdpr      %%pil, %0\n\t" \
-                            "wrpr      15, %%pil" \
-                            : "=r" (retval) \
-                            : : "memory"); \
-       retval; \
-})
-
-#define local_save_flags(flags)                ((flags) = getipl())
-#define local_irq_save(flags)          ((flags) = read_pil_and_cli())
-#define local_irq_restore(flags)               setipl((flags))
-
-/* On sparc64 IRQ flags are the PIL register.  A value of zero
- * means all interrupt levels are enabled, any other value means
- * only IRQ levels greater than that value will be received.
- * Consequently this means that the lowest IRQ level is one.
- */
-#define irqs_disabled()                \
-({     unsigned long flags;    \
-       local_save_flags(flags);\
-       (flags > 0);            \
-})
-
 #define nop()          __asm__ __volatile__ ("nop")
 
 #define read_barrier_depends()         do { } while(0)
index f2352606a79f5a1dd6e0f8ff305d6becc1665ce7..c2a16e1884992a0c9bd13dbbf774731eb1fe2ecf 100644 (file)
 #endif
 #define BREAKPOINT_TRAP TRAP(breakpoint_trap)
 
+#ifdef CONFIG_TRACE_IRQFLAGS
+
+#define TRAP_IRQ(routine, level)                       \
+       rdpr    %pil, %g2;                              \
+       wrpr    %g0, 15, %pil;                          \
+       sethi   %hi(1f-4), %g7;                         \
+       ba,pt   %xcc, etrap_irq;                        \
+        or     %g7, %lo(1f-4), %g7;                    \
+       nop;                                            \
+       nop;                                            \
+       nop;                                            \
+       .subsection     2;                              \
+1:     call    trace_hardirqs_off;                     \
+        nop;                                           \
+       mov     level, %o0;                             \
+       call    routine;                                \
+        add    %sp, PTREGS_OFF, %o1;                   \
+       ba,a,pt %xcc, rtrap_irq;                        \
+       .previous;
+
+#define TICK_SMP_IRQ                                   \
+       rdpr    %pil, %g2;                              \
+       wrpr    %g0, 15, %pil;                          \
+       sethi   %hi(1f-4), %g7;                         \
+       ba,pt   %xcc, etrap_irq;                        \
+        or     %g7, %lo(1f-4), %g7;                    \
+       nop;                                            \
+       nop;                                            \
+       nop;                                            \
+       .subsection     2;                              \
+1:     call    trace_hardirqs_off;                     \
+        nop;                                           \
+       call    smp_percpu_timer_interrupt;             \
+        add    %sp, PTREGS_OFF, %o0;                   \
+       ba,a,pt %xcc, rtrap_irq;                        \
+       .previous;
+
+#else
+
 #define TRAP_IRQ(routine, level)                       \
        rdpr    %pil, %g2;                              \
        wrpr    %g0, 15, %pil;                          \
-       b,pt    %xcc, etrap_irq;                        \
+       ba,pt   %xcc, etrap_irq;                        \
         rd     %pc, %g7;                               \
        mov     level, %o0;                             \
        call    routine;                                \
        rdpr    %pil, %g2;                              \
        wrpr    %g0, 15, %pil;                          \
        sethi   %hi(109f), %g7;                         \
-       b,pt    %xcc, etrap_irq;                        \
+       ba,pt   %xcc, etrap_irq;                        \
 109:    or     %g7, %lo(109b), %g7;                    \
        call    smp_percpu_timer_interrupt;             \
         add    %sp, PTREGS_OFF, %o0;                   \
        ba,a,pt %xcc, rtrap_irq;
 
+#endif
+
 #define TRAP_IVEC TRAP_NOSAVE(do_ivec)
 
 #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
index 5c8f49280dbcc273d718bfd1d9895403910a3ca5..2facec5914d2cb4793b96bc4cdfdbc908341b861 100644 (file)
@@ -47,6 +47,7 @@ extern int __node_distance(int, int);
        .flags                  = SD_LOAD_BALANCE       \
                                | SD_BALANCE_FORK       \
                                | SD_BALANCE_EXEC       \
+                               | SD_SERIALIZE          \
                                | SD_WAKE_BALANCE,      \
        .last_balance           = jiffies,              \
        .balance_interval       = 1,                    \
diff --git a/include/asm-xtensa/asmmacro.h b/include/asm-xtensa/asmmacro.h
new file mode 100644 (file)
index 0000000..76915ca
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * include/asm-xtensa/asmmacro.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ASMMACRO_H
+#define _XTENSA_ASMMACRO_H
+
+#include <asm/variant/core.h>
+
+/*
+ * Some little helpers for loops. Use zero-overhead-loops
+ * where applicable and if supported by the processor.
+ *
+ * __loopi ar, at, size, inc
+ *         ar  register initialized with the start address
+ *        at   scratch register used by macro
+ *        size size immediate value
+ *        inc  increment
+ *
+ * __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond]
+ *        ar   register initialized with the start address
+ *        as   register initialized with the size
+ *        at   scratch register use by macro
+ *        inc_log2     increment [in log2]
+ *        mask_log2    mask [in log2]
+ *        cond         true condition (used in loop'cond')
+ *        ncond        false condition (used in b'ncond')
+ *
+ * __loop  as
+ *        restart loop. 'as' register must not have been modified!
+ *
+ * __endla ar, at, incr
+ *        ar   start address (modified)
+ *        as   scratch register used by macro
+ *        inc  increment
+ */
+
+/*
+ * loop for given size as immediate
+ */
+
+       .macro  __loopi ar, at, size, incr
+
+#if XCHAL_HAVE_LOOPS
+               movi    \at, ((\size + \incr - 1) / (\incr))
+               loop    \at, 99f
+#else
+               addi    \at, \ar, \size
+               98:
+#endif
+
+       .endm
+
+/*
+ * loop for given size in register
+ */
+
+       .macro  __loops ar, as, at, incr_log2, mask_log2, cond, ncond
+
+#if XCHAL_HAVE_LOOPS
+               .ifgt \incr_log2 - 1
+                       addi    \at, \as, (1 << \incr_log2) - 1
+                       .ifnc \mask_log2,
+                               extui   \at, \at, \incr_log2, \mask_log2
+                       .else
+                               srli    \at, \at, \incr_log2
+                       .endif
+               .endif
+               loop\cond       \at, 99f
+#else
+               .ifnc \mask_log2,
+                       extui   \at, \as, \incr_log2, \mask_log2
+               .else
+                       .ifnc \ncond,
+                               srli    \at, \as, \incr_log2
+                       .endif
+               .endif
+               .ifnc \ncond,
+                       b\ncond \at, 99f
+
+               .endif
+               .ifnc \mask_log2,
+                       slli    \at, \at, \incr_log2
+                       add     \at, \ar, \at
+               .else
+                       add     \at, \ar, \as
+               .endif
+#endif
+               98:
+
+       .endm
+
+/*
+ * loop from ar to ax
+ */
+
+       .macro  __loopt ar, as, at, incr_log2
+
+#if XCHAL_HAVE_LOOPS
+               sub     \at, \as, \ar
+               .ifgt   \incr_log2 - 1
+                       addi    \at, \at, (1 << \incr_log2) - 1
+                       srli    \at, \at, \incr_log2
+               .endif
+               loop    \at, 99f
+#else
+               98:
+#endif
+
+       .endm
+
+/*
+ * restart loop. registers must be unchanged
+ */
+
+       .macro  __loop  as
+
+#if XCHAL_HAVE_LOOPS
+               loop    \as, 99f
+#else
+               98:
+#endif
+
+       .endm
+
+/*
+ * end of loop with no increment of the address.
+ */
+
+       .macro  __endl  ar, as
+#if !XCHAL_HAVE_LOOPS
+               bltu    \ar, \as, 98b
+#endif
+               99:
+       .endm
+
+/*
+ * end of loop with increment of the address.
+ */
+
+       .macro  __endla ar, as, incr
+               addi    \ar, \ar, \incr
+               __endl  \ar \as
+       .endm
+
+
+#endif /* _XTENSA_ASMMACRO_H */
index 56703659b204602ff612f9696071d0aed0c8a159..3e52d72712f1f7e632506e428b0cb9422ce87eac 100644 (file)
 #ifndef _XTENSA_BUG_H
 #define _XTENSA_BUG_H
 
-#include <linux/stringify.h>
-
-#define ILL    __asm__ __volatile__ (".byte 0,0,0\n")
-
-#ifdef CONFIG_KALLSYMS
-# define BUG() do {                                                    \
-       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);           \
-       ILL;                                                            \
-} while (0)
-#else
-# define BUG() do {                                                    \
-       printk("kernel BUG!\n");                                        \
-       ILL;                                                            \
-} while (0)
-#endif
-
-#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-#define PAGE_BUG(page) do {  BUG(); } while (0)
-#define WARN_ON(condition) do {                                                   \
-  if (unlikely((condition)!=0)) {                                         \
-    printk ("Warning in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
-      dump_stack();                                                       \
-  }                                                                       \
-} while (0)
+#include <asm-generic/bug.h>
 
 #endif /* _XTENSA_BUG_H */
index 0b1552569aae251f8c4c232858000abacf133514..0f540a5f4c01c7f6ef799a9b1c997348ce3a6b22 100644 (file)
 #ifndef _XTENSA_BYTEORDER_H
 #define _XTENSA_BYTEORDER_H
 
-#include <asm/processor.h>
 #include <asm/types.h>
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
 {
     __u32 res;
     /* instruction sequence from Xtensa ISA release 2/2000 */
@@ -29,7 +28,7 @@ static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
     return res;
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
 {
     /* Given that 'short' values are signed (i.e., can be negative),
      * we cannot assume that the upper 16-bits of the register are
index 1e79c0e2746037379745c21533de616c70569a5d..1c4a78f29ae2dc11fef33433118ebbf8d3f3e694 100644 (file)
@@ -4,7 +4,6 @@
  * 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.
- * 2 of the License, or (at your option) any later version.
  *
  * (C) 2001 - 2005 Tensilica Inc.
  */
 #ifndef _XTENSA_CACHE_H
 #define _XTENSA_CACHE_H
 
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
-#if XCHAL_ICACHE_SIZE > 0
-# if (XCHAL_ICACHE_SIZE % (XCHAL_ICACHE_LINESIZE*XCHAL_ICACHE_WAYS*4)) != 0
-#  error cache configuration outside expected/supported range!
-# endif
-#endif
+#define L1_CACHE_SHIFT XCHAL_DCACHE_LINEWIDTH
+#define L1_CACHE_BYTES XCHAL_DCACHE_LINESIZE
+#define SMP_CACHE_BYTES        L1_CACHE_BYTES
 
-#if XCHAL_DCACHE_SIZE > 0
-# if (XCHAL_DCACHE_SIZE % (XCHAL_DCACHE_LINESIZE*XCHAL_DCACHE_WAYS*4)) != 0
-#  error cache configuration outside expected/supported range!
-# endif
-#endif
+#define DCACHE_WAY_SIZE        (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS)
+#define ICACHE_WAY_SIZE        (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS)
 
-#define L1_CACHE_SHIFT         XCHAL_CACHE_LINEWIDTH_MAX
-#define L1_CACHE_BYTES         XCHAL_CACHE_LINESIZE_MAX
 
 #endif /* _XTENSA_CACHE_H */
diff --git a/include/asm-xtensa/cacheasm.h b/include/asm-xtensa/cacheasm.h
new file mode 100644 (file)
index 0000000..2c20a58
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * include/asm-xtensa/cacheasm.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2006 Tensilica Inc.
+ */
+
+#include <asm/cache.h>
+#include <asm/asmmacro.h>
+#include <linux/stringify.h>
+
+/*
+ * Define cache functions as macros here so that they can be used
+ * by the kernel and boot loader. We should consider moving them to a
+ * library that can be linked by both.
+ *
+ * Locking
+ *
+ *   ___unlock_dcache_all
+ *   ___unlock_icache_all
+ *
+ * Flush and invaldating
+ *
+ *   ___flush_invalidate_dcache_{all|range|page}
+ *   ___flush_dcache_{all|range|page}
+ *   ___invalidate_dcache_{all|range|page}
+ *   ___invalidate_icache_{all|range|page}
+ *
+ */
+
+       .macro  __loop_cache_all ar at insn size line_width
+
+       movi    \ar, 0
+
+       __loopi \ar, \at, \size, (4 << (\line_width))
+       \insn   \ar, 0 << (\line_width)
+       \insn   \ar, 1 << (\line_width)
+       \insn   \ar, 2 << (\line_width)
+       \insn   \ar, 3 << (\line_width)
+       __endla \ar, \at, 4 << (\line_width)
+
+       .endm
+
+
+       .macro  __loop_cache_range ar as at insn line_width
+
+       extui   \at, \ar, 0, \line_width
+       add     \as, \as, \at
+
+       __loops \ar, \as, \at, \line_width
+       \insn   \ar, 0
+       __endla \ar, \at, (1 << (\line_width))
+
+       .endm
+
+
+       .macro  __loop_cache_page ar at insn line_width
+
+       __loopi \ar, \at, PAGE_SIZE, 4 << (\line_width)
+       \insn   \ar, 0 << (\line_width)
+       \insn   \ar, 1 << (\line_width)
+       \insn   \ar, 2 << (\line_width)
+       \insn   \ar, 3 << (\line_width)
+       __endla \ar, \at, 4 << (\line_width)
+
+       .endm
+
+
+#if XCHAL_DCACHE_LINE_LOCKABLE
+
+       .macro  ___unlock_dcache_all ar at
+
+       __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+#endif
+
+#if XCHAL_ICACHE_LINE_LOCKABLE
+
+       .macro  ___unlock_icache_all ar at
+
+       __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE XCHAL_ICACHE_LINEWIDTH
+
+       .endm
+#endif
+
+       .macro  ___flush_invalidate_dcache_all ar at
+
+       __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___flush_dcache_all ar at
+
+       __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_dcache_all ar at
+
+       __loop_cache_all \ar \at dii __stringify(DCACHE_WAY_SIZE) \
+                        XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_icache_all ar at
+
+       __loop_cache_all \ar \at iii __stringify(ICACHE_WAY_SIZE) \
+                        XCHAL_ICACHE_LINEWIDTH
+
+       .endm
+
+
+
+       .macro  ___flush_invalidate_dcache_range ar as at
+
+       __loop_cache_range \ar \as \at dhwbi XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___flush_dcache_range ar as at
+
+       __loop_cache_range \ar \as \at dhwb XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_dcache_range ar as at
+
+       __loop_cache_range \ar \as \at dhi XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_icache_range ar as at
+
+       __loop_cache_range \ar \as \at ihi XCHAL_ICACHE_LINEWIDTH
+
+       .endm
+
+
+
+       .macro  ___flush_invalidate_dcache_page ar as
+
+       __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro ___flush_dcache_page ar as
+
+       __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_dcache_page ar as
+
+       __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH
+
+       .endm
+
+
+       .macro  ___invalidate_icache_page ar as
+
+       __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH
+
+       .endm
+
index 44a36e087844009efc69d154f79e95df3b4f8d88..337765b629de0dd38e42c2b714b4858ce7b2ef03 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * (C) 2001 - 2005 Tensilica Inc.
+ * (C) 2001 - 2006 Tensilica Inc.
  */
 
 #ifndef _XTENSA_CACHEFLUSH_H
index 5435aff9a4b7c807d955540e7958260d8e3e0262..23534c60b3a4a2878c73fd9aeba76f717bc9c9ef 100644 (file)
@@ -12,7 +12,7 @@
 #define _XTENSA_CHECKSUM_H
 
 #include <linux/in6.h>
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
 /*
  * computes the checksum of a memory block at buff, length len,
index 5093034723becd3df1ad1a7b2558097ad7230fb2..bd09ec02d57f941182f2de62a4de7476c36250d2 100644 (file)
 #ifndef _XTENSA_COPROCESSOR_H
 #define _XTENSA_COPROCESSOR_H
 
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
+#include <asm/variant/tie.h>
+
+#if !XCHAL_HAVE_CP
+
+#define XTENSA_CP_EXTRA_OFFSET         0
+#define XTENSA_CP_EXTRA_ALIGN  1       /* must be a power of 2 */
+#define XTENSA_CP_EXTRA_SIZE   0
+
+#else
 
 #define XTOFS(last_start,last_size,align) \
        ((last_start+last_size+align-1) & -align)
@@ -67,4 +76,6 @@ extern void save_coprocessor_registers(void*, int);
 # endif
 #endif
 
+#endif
+
 #endif /* _XTENSA_COPROCESSOR_H */
index db2633f67789ad994df5b0fb9527c5d1f347e7bd..e30f3abf48f0a60d889b852088c8493ef8509597 100644 (file)
@@ -12,7 +12,6 @@
 #define _XTENSA_DMA_H
 
 #include <asm/io.h>            /* need byte IO */
-#include <xtensa/config/core.h>
 
 /*
  * This is only to be defined if we have PC-like DMA.
@@ -44,7 +43,9 @@
  *     enters another area, and virt_to_phys() may not return
  *     the value desired).
  */
-#define MAX_DMA_ADDRESS                (PAGE_OFFSET + XCHAL_KSEG_CACHED_SIZE - 1)
+
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + XCHAL_KIO_SIZE - 1)
+
 
 /* Reserve and release a DMA channel */
 extern int request_dma(unsigned int dmanr, const char * device_id);
index de0667453b2ecb28ef6f6cac3b70a31af29b4282..f0f9fd8560a5f905aebd43e321688e771dc572fe 100644 (file)
@@ -13,9 +13,8 @@
 #ifndef _XTENSA_ELF_H
 #define _XTENSA_ELF_H
 
+#include <asm/variant/core.h>
 #include <asm/ptrace.h>
-#include <asm/coprocessor.h>
-#include <xtensa/config/core.h>
 
 /* Xtensa processor ELF architecture-magic number */
 
@@ -118,11 +117,15 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
  * using memcpy().  But we do allow space for such alignment,
  * to allow optimizations of layout and copying.
  */
-
+#if 0
 #define TOTAL_FPREGS_SIZE                                              \
        (4 + XTENSA_CPE_LTABLE_SIZE + XTENSA_CP_EXTRA_SIZE)
 #define ELF_NFPREG                                                     \
        ((TOTAL_FPREGS_SIZE + sizeof(elf_fpreg_t) - 1) / sizeof(elf_fpreg_t))
+#else
+#define TOTAL_FPREGS_SIZE      0
+#define ELF_NFPREG             0
+#endif
 
 typedef unsigned int elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
index ec066ae96caf166c09433442f2ac516d2c501c8c..0609fc691b72b97b3d4511f4993788560561b964 100644 (file)
 
 /* open/fcntl - O_SYNC is only implemented on blocks devices and on files
    located on an ext2 file system */
-#define O_APPEND       0x0008
-#define O_SYNC         0x0010
-#define O_NONBLOCK     0x0080
-#define O_CREAT         0x0100 /* not fcntl */
-#define O_EXCL         0x0400  /* not fcntl */
-#define O_NOCTTY       0x0800  /* not fcntl */
-#define FASYNC         0x1000  /* fcntl, for BSD compatibility */
-#define O_LARGEFILE    0x2000  /* allow large file opens - currently ignored */
-#define O_DIRECT       0x8000  /* direct disk access hint - currently ignored*/
-#define O_NOATIME      0x100000
-
-#define F_GETLK                14
-#define F_GETLK64       15
+#define O_ACCMODE         0003
+#define O_RDONLY            00
+#define O_WRONLY            01
+#define O_RDWR              02
+#define O_CREAT                   0100 /* not fcntl */
+#define O_EXCL            0200 /* not fcntl */
+#define O_NOCTTY          0400 /* not fcntl */
+#define O_TRUNC                  01000 /* not fcntl */
+#define O_APPEND         02000
+#define O_NONBLOCK       04000
+#define O_NDELAY       O_NONBLOCK
+#define O_SYNC          010000
+#define FASYNC          020000 /* fcntl, for BSD compatibility */
+#define O_DIRECT        040000 /* direct disk access hint */
+#define O_LARGEFILE    0100000
+#define O_DIRECTORY    0200000 /* must be a directory */
+#define O_NOFOLLOW     0400000 /* don't follow links */
+#define O_NOATIME      01000000
+
+#define F_DUPFD                0       /* dup */
+#define F_GETFD                1       /* get close_on_exec */
+#define F_SETFD                2       /* set/clear close_on_exec */
+#define F_GETFL                3       /* get file->f_flags */
+#define F_SETFL                4       /* set file->f_flags */
+#define F_GETLK                5
 #define F_SETLK                6
 #define F_SETLKW       7
-#define F_SETLK64       16
-#define F_SETLKW64      17
 
-#define F_SETOWN       24      /*  for sockets. */
-#define F_GETOWN       23      /*  for sockets. */
+#define F_SETOWN       8       /*  for sockets. */
+#define F_GETOWN       9       /*  for sockets. */
+#define F_SETSIG       10      /*  for sockets. */
+#define F_GETSIG       11      /*  for sockets. */
+
+#define F_GETLK64      12      /*  using 'struct flock64' */
+#define F_SETLK64      13
+#define F_SETLKW64     14
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK                0
+#define F_WRLCK                1
+#define F_UNLCK                2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK                4       /* or 3 */
+#define F_SHLCK                8       /* or 4 */
 
-typedef struct flock {
+/* for leases */
+#define F_INPROGRESS   16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH                1       /* shared lock */
+#define LOCK_EX                2       /* exclusive lock */
+#define LOCK_NB                4       /* or'd with one of the above to prevent
+                                  blocking */
+#define LOCK_UN                8       /* remove lock */
+
+#define LOCK_MAND      32      /* This is a mandatory flock */
+#define LOCK_READ      64      /* ... Which allows concurrent read operations */
+#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
+#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
+
+struct flock {
        short l_type;
        short l_whence;
-       __kernel_off_t l_start;
-       __kernel_off_t l_len;
-       long  l_sysid;
-       __kernel_pid_t l_pid;
-       long  pad[4];
-} flock_t;
+       off_t l_start;
+       off_t l_len;
+       pid_t l_pid;
+};
 
 struct flock64 {
        short  l_type;
        short  l_whence;
-       __kernel_off_t l_start;
-       __kernel_off_t l_len;
+       loff_t l_start;
+       loff_t l_len;
        pid_t  l_pid;
 };
 
-#define HAVE_ARCH_STRUCT_FLOCK
-#define HAVE_ARCH_STRUCT_FLOCK64
-
-#include <asm-generic/fcntl.h>
+#define F_LINUX_SPECIFIC_BASE  1024
 
 #endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/fixmap.h b/include/asm-xtensa/fixmap.h
deleted file mode 100644 (file)
index 4423b8a..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * include/asm-xtensa/fixmap.h
- *
- * 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.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_FIXMAP_H
-#define _XTENSA_FIXMAP_H
-
-#include <asm/processor.h>
-
-#ifdef CONFIG_MMU
-
-/*
- * Here we define all the compile-time virtual addresses.
- */
-
-#if XCHAL_SEG_MAPPABLE_VADDR != 0
-# error "Current port requires virtual user space starting at 0"
-#endif
-#if XCHAL_SEG_MAPPABLE_SIZE < 0x80000000
-# error "Current port requires at least 0x8000000 bytes for user space"
-#endif
-
-/* Verify instruction/data ram/rom and xlmi don't overlay vmalloc space. */
-
-#define __IN_VMALLOC(addr)                                             \
-       (((addr) >= VMALLOC_START) && ((addr) < VMALLOC_END))
-#define __SPAN_VMALLOC(start,end)                                      \
-       (((start) < VMALLOC_START) && ((end) >= VMALLOC_END))
-#define INSIDE_VMALLOC(start,end)                                      \
-       (__IN_VMALLOC((start)) || __IN_VMALLOC(end) || __SPAN_VMALLOC((start),(end)))
-
-#if XCHAL_NUM_INSTROM
-# if XCHAL_NUM_INSTROM == 1
-#  if INSIDE_VMALLOC(XCHAL_INSTROM0_VADDR,XCHAL_INSTROM0_VADDR+XCHAL_INSTROM0_SIZE)
-#   error vmalloc range conflicts with instrom0
-#  endif
-# endif
-# if XCHAL_NUM_INSTROM == 2
-#  if INSIDE_VMALLOC(XCHAL_INSTROM1_VADDR,XCHAL_INSTROM1_VADDR+XCHAL_INSTROM1_SIZE)
-#   error vmalloc range conflicts with instrom1
-#  endif
-# endif
-#endif
-
-#if XCHAL_NUM_INSTRAM
-# if XCHAL_NUM_INSTRAM == 1
-#  if INSIDE_VMALLOC(XCHAL_INSTRAM0_VADDR,XCHAL_INSTRAM0_VADDR+XCHAL_INSTRAM0_SIZE)
-#   error vmalloc range conflicts with instram0
-#  endif
-# endif
-# if XCHAL_NUM_INSTRAM == 2
-#  if INSIDE_VMALLOC(XCHAL_INSTRAM1_VADDR,XCHAL_INSTRAM1_VADDR+XCHAL_INSTRAM1_SIZE)
-#   error vmalloc range conflicts with instram1
-#  endif
-# endif
-#endif
-
-#if XCHAL_NUM_DATAROM
-# if XCHAL_NUM_DATAROM == 1
-#  if INSIDE_VMALLOC(XCHAL_DATAROM0_VADDR,XCHAL_DATAROM0_VADDR+XCHAL_DATAROM0_SIZE)
-#   error vmalloc range conflicts with datarom0
-#  endif
-# endif
-# if XCHAL_NUM_DATAROM == 2
-#  if INSIDE_VMALLOC(XCHAL_DATAROM1_VADDR,XCHAL_DATAROM1_VADDR+XCHAL_DATAROM1_SIZE)
-#   error vmalloc range conflicts with datarom1
-#  endif
-# endif
-#endif
-
-#if XCHAL_NUM_DATARAM
-# if XCHAL_NUM_DATARAM == 1
-#  if INSIDE_VMALLOC(XCHAL_DATARAM0_VADDR,XCHAL_DATARAM0_VADDR+XCHAL_DATARAM0_SIZE)
-#   error vmalloc range conflicts with dataram0
-#  endif
-# endif
-# if XCHAL_NUM_DATARAM == 2
-#  if INSIDE_VMALLOC(XCHAL_DATARAM1_VADDR,XCHAL_DATARAM1_VADDR+XCHAL_DATARAM1_SIZE)
-#   error vmalloc range conflicts with dataram1
-#  endif
-# endif
-#endif
-
-#if XCHAL_NUM_XLMI
-# if XCHAL_NUM_XLMI == 1
-#  if INSIDE_VMALLOC(XCHAL_XLMI0_VADDR,XCHAL_XLMI0_VADDR+XCHAL_XLMI0_SIZE)
-#   error vmalloc range conflicts with xlmi0
-#  endif
-# endif
-# if XCHAL_NUM_XLMI == 2
-#  if INSIDE_VMALLOC(XCHAL_XLMI1_VADDR,XCHAL_XLMI1_VADDR+XCHAL_XLMI1_SIZE)
-#   error vmalloc range conflicts with xlmi1
-#  endif
-# endif
-#endif
-
-#if (XCHAL_NUM_INSTROM > 2) || \
-    (XCHAL_NUM_INSTRAM > 2) || \
-    (XCHAL_NUM_DATARAM > 2) || \
-    (XCHAL_NUM_DATAROM > 2) || \
-    (XCHAL_NUM_XLMI    > 2)
-# error Insufficient checks on vmalloc above for more than 2 devices
-#endif
-
-/*
- * USER_VM_SIZE does not necessarily equal TASK_SIZE.  We bumped
- * TASK_SIZE down to 0x4000000 to simplify the handling of windowed
- * call instructions (currently limited to a range of 1 GByte).  User
- * tasks may very well reclaim the VM space from 0x40000000 to
- * 0x7fffffff in the future, so we do not want the kernel becoming
- * accustomed to having any of its stuff (e.g., page tables) in this
- * region.  This VM region is no-man's land for now.
- */
-
-#define USER_VM_START          XCHAL_SEG_MAPPABLE_VADDR
-#define USER_VM_SIZE           0x80000000
-
-/*  Size of page table:  */
-
-#define PGTABLE_SIZE_BITS      (32 - XCHAL_MMU_MIN_PTE_PAGE_SIZE + 2)
-#define PGTABLE_SIZE           (1L << PGTABLE_SIZE_BITS)
-
-/*  All kernel-mappable space:  */
-
-#define KERNEL_ALLMAP_START    (USER_VM_START + USER_VM_SIZE)
-#define KERNEL_ALLMAP_SIZE     (XCHAL_SEG_MAPPABLE_SIZE - KERNEL_ALLMAP_START)
-
-/*  Carve out page table at start of kernel-mappable area:  */
-
-#if KERNEL_ALLMAP_SIZE < PGTABLE_SIZE
-#error "Gimme some space for page table!"
-#endif
-#define PGTABLE_START          KERNEL_ALLMAP_START
-
-/*  Remaining kernel-mappable space:  */
-
-#define KERNEL_MAPPED_START    (KERNEL_ALLMAP_START + PGTABLE_SIZE)
-#define KERNEL_MAPPED_SIZE     (KERNEL_ALLMAP_SIZE - PGTABLE_SIZE)
-
-#if KERNEL_MAPPED_SIZE < 0x01000000    /* 16 MB is arbitrary for now */
-# error "Shouldn't the kernel have at least *some* mappable space?"
-#endif
-
-#define MAX_LOW_MEMORY         XCHAL_KSEG_CACHED_SIZE
-
-#endif
-
-/*
- *  Some constants used elsewhere, but perhaps only in Xtensa header
- *  files, so maybe we can get rid of some and access compile-time HAL
- *  directly...
- *
- *  Note:  We assume that system RAM is located at the very start of the
- *        kernel segments !!
- */
-#define KERNEL_VM_LOW           XCHAL_KSEG_CACHED_VADDR
-#define KERNEL_VM_HIGH          XCHAL_KSEG_BYPASS_VADDR
-#define KERNEL_SPACE            XCHAL_KSEG_CACHED_VADDR
-
-/*
- * Returns the physical/virtual addresses of the kernel space
- * (works with the cached kernel segment only, which is the
- *  one normally used for kernel operation).
- */
-
-/*                     PHYSICAL        BYPASS          CACHED
- *
- *  bypass vaddr       bypass paddr    *               cached vaddr
- *  cached vaddr       cached paddr    bypass vaddr    *
- *  bypass paddr       *               bypass vaddr    cached vaddr
- *  cached paddr       *               bypass vaddr    cached vaddr
- *  other              *               *               *
- */
-
-#define PHYSADDR(a)                                                          \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR                                   \
-  && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
-    (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_PADDR :       \
-    ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR                                \
-     && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
-        (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_PADDR :   \
-       (unsigned)(a))
-
-#define BYPASS_ADDR(a)                                                       \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR                                   \
-  && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
-    (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_VADDR :       \
-    ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR                                \
-     && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
-        (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_BYPASS_VADDR :   \
-        ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR                            \
-         && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_CACHED_SIZE)?  \
-            (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_BYPASS_VADDR:  \
-           (unsigned)(a))
-
-#define CACHED_ADDR(a)                                                       \
-(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR                                   \
-  && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ?      \
-    (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_CACHED_VADDR :       \
-    ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR                                \
-     && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ?   \
-        (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_VADDR :   \
-        ((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR                            \
-         && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_BYPASS_SIZE) ? \
-            (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_CACHED_VADDR : \
-           (unsigned)(a))
-
-#define PHYSADDR_IO(a)                                                       \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR                                    \
-  && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
-    (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_PADDR :        \
-    ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR                                 \
-     && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ?     \
-        (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_PADDR :     \
-       (unsigned)(a))
-
-#define BYPASS_ADDR_IO(a)                                                    \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR                                    \
-  && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
-    (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_VADDR :        \
-    ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR                                 \
-     && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ?     \
-        (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_BYPASS_VADDR :     \
-        ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR                             \
-         && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
-            (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_BYPASS_VADDR : \
-           (unsigned)(a))
-
-#define CACHED_ADDR_IO(a)                                                    \
-(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR                                    \
-  && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ?       \
-    (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_CACHED_VADDR :        \
-    ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR                                 \
-     && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ?     \
-        (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_VADDR :     \
-        ((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR                             \
-         && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
-            (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_CACHED_VADDR : \
-           (unsigned)(a))
-
-#endif /* _XTENSA_ADDRSPACE_H */
-
-
-
-
-
index 556e5eed34f54af663fd01b7200b1c5310beece3..31ffc3f119c1cd60254325c83ca08a53b76d3947 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/include/asm-xtensa/io.h
+ * include/asm-xtensa/io.h
  *
  * 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
 #include <asm/byteorder.h>
 
 #include <linux/types.h>
-#include <asm/fixmap.h>
-
-#define _IO_BASE 0
 
+#define XCHAL_KIO_CACHED_VADDR 0xf0000000
+#define XCHAL_KIO_BYPASS_VADDR 0xf8000000
+#define XCHAL_KIO_PADDR                0xf0000000
+#define XCHAL_KIO_SIZE         0x08000000
 
 /*
  * swap functions to change byte order from little-endian to big-endian and
@@ -42,40 +43,43 @@ static inline unsigned int _swapl (unsigned int v)
 
 static inline unsigned long virt_to_phys(volatile void * address)
 {
-       return PHYSADDR((unsigned long)address);
+       return __pa(address);
 }
 
 static inline void * phys_to_virt(unsigned long address)
 {
-       return (void*) CACHED_ADDR(address);
+       return __va(address);
 }
 
 /*
- * IO bus memory addresses are also 1:1 with the physical address
+ * virt_to_bus and bus_to_virt are deprecated.
  */
 
-static inline unsigned long virt_to_bus(volatile void * address)
-{
-       return PHYSADDR((unsigned long)address);
-}
-
-static inline void * bus_to_virt (unsigned long address)
-{
-       return (void *) CACHED_ADDR(address);
-}
+#define virt_to_bus(x) virt_to_phys(x)
+#define bus_to_virt(x) phys_to_virt(x)
 
 /*
- * Change "struct page" to physical address.
+ * Return the virtual (cached) address for the specified bus memory.
+ * Note that we currently don't support any address outside the KIO segment.
  */
 
 static inline void *ioremap(unsigned long offset, unsigned long size)
 {
-        return (void *) CACHED_ADDR_IO(offset);
+       if (offset >= XCHAL_KIO_PADDR
+           && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
+               return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR);
+
+       else
+               BUG();
 }
 
 static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
 {
-        return (void *) BYPASS_ADDR_IO(offset);
+       if (offset >= XCHAL_KIO_PADDR
+           && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
+               return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR);
+       else
+               BUG();
 }
 
 static inline void iounmap(void *addr)
@@ -121,9 +125,6 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
           *(__force volatile __u32 *)(addr) = b;
 }
 
-
-
-
 /* These are the definitions for the x86 IO instructions
  * inb/inw/inl/outb/outw/outl, the "string" versions
  * insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions
@@ -131,11 +132,11 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
  * The macros don't do byte-swapping.
  */
 
-#define inb(port)              readb((u8 *)((port)+_IO_BASE))
-#define outb(val, port)                writeb((val),(u8 *)((unsigned long)(port)+_IO_BASE))
-#define inw(port)              readw((u16 *)((port)+_IO_BASE))
-#define outw(val, port)                writew((val),(u16 *)((unsigned long)(port)+_IO_BASE))
-#define inl(port)              readl((u32 *)((port)+_IO_BASE))
+#define inb(port)              readb((u8 *)((port)))
+#define outb(val, port)                writeb((val),(u8 *)((unsigned long)(port)))
+#define inw(port)              readw((u16 *)((port)))
+#define outw(val, port)                writew((val),(u16 *)((unsigned long)(port)))
+#define inl(port)              readl((u32 *)((port)))
 #define outl(val, port)                writel((val),(u32 *)((unsigned long)(port)))
 
 #define inb_p(port)            inb((port))
@@ -180,14 +181,13 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
 
 
 /*
- *  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- *   * access
- *    */
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem access
+ */
 #define xlate_dev_mem_ptr(p)    __va(p)
 
 /*
- *  * Convert a virtual cached pointer to an uncached pointer
- *   */
+ * Convert a virtual cached pointer to an uncached pointer
+ */
 #define xlate_dev_kmem_ptr(p)   p
 
 
index 049fde7e752d3a098d389600e5d9b3fe8b2aa50f..fc73b7f11aff2c5ad61c7a78024c486293ec24f7 100644 (file)
@@ -12,8 +12,7 @@
 #define _XTENSA_IRQ_H
 
 #include <asm/platform/hardware.h>
-
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
 #ifndef PLATFORM_NR_IRQS
 # define PLATFORM_NR_IRQS 0
@@ -27,10 +26,5 @@ static __inline__ int irq_canonicalize(int irq)
 }
 
 struct irqaction;
-#if 0 // FIXME
-extern void disable_irq_nosync(unsigned int);
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-#endif
 
 #endif /* _XTENSA_IRQ_H */
diff --git a/include/asm-xtensa/irq_regs.h b/include/asm-xtensa/irq_regs.h
new file mode 100644 (file)
index 0000000..3dd9c0b
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
index af683a74a4ec74884ca7c8fafa42768d84f8b623..f14851f086c39db5cb6fe0e7892a7278f050772f 100644 (file)
 #include <linux/stringify.h>
 
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-/*
- * Linux was ported to Xtensa assuming all auto-refill ways in set 0
- * had the same properties (a very likely assumption).  Multiple sets
- * of auto-refill ways will still work properly, but not as optimally
- * as the Xtensa designer may have assumed.
- *
- * We make this case a hard #error, killing the kernel build, to alert
- * the developer to this condition (which is more likely an error).
- * You super-duper clever developers can change it to a warning or
- * remove it altogether if you think you know what you're doing.  :)
- */
+#define XCHAL_MMU_ASID_BITS    8
 
 #if (XCHAL_HAVE_TLBS != 1)
 # error "Linux must have an MMU!"
 #endif
 
-#if ((XCHAL_ITLB_ARF_WAYS == 0) || (XCHAL_DTLB_ARF_WAYS == 0))
-# error "MMU must have auto-refill ways"
-#endif
-
-#if ((XCHAL_ITLB_ARF_SETS != 1) || (XCHAL_DTLB_ARF_SETS != 1))
-# error Linux may not use all auto-refill ways as efficiently as you think
-#endif
-
-#if (XCHAL_MMU_MAX_PTE_PAGE_SIZE != XCHAL_MMU_MIN_PTE_PAGE_SIZE)
-# error Only one page size allowed!
-#endif
-
 extern unsigned long asid_cache;
-extern pgd_t *current_pgd;
-
-/*
- * Define the number of entries per auto-refill way in set 0 of both I and D
- * TLBs.  We deal only with set 0 here (an assumption further explained in
- * assertions.h).  Also, define the total number of ARF entries in both TLBs.
- */
-
-#define ITLB_ENTRIES_PER_ARF_WAY  (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES))
-#define DTLB_ENTRIES_PER_ARF_WAY  (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES))
-
-#define ITLB_ENTRIES                                                   \
-       (ITLB_ENTRIES_PER_ARF_WAY * (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,WAYS)))
-#define DTLB_ENTRIES                                                   \
-       (DTLB_ENTRIES_PER_ARF_WAY * (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,WAYS)))
-
-
-/*
- * SMALLEST_NTLB_ENTRIES is the smaller of ITLB_ENTRIES and DTLB_ENTRIES.
- * In practice, they are probably equal.  This macro simplifies function
- * flush_tlb_range().
- */
-
-#if (DTLB_ENTRIES < ITLB_ENTRIES)
-# define SMALLEST_NTLB_ENTRIES  DTLB_ENTRIES
-#else
-# define SMALLEST_NTLB_ENTRIES  ITLB_ENTRIES
-#endif
-
-
-/*
- * asid_cache tracks only the ASID[USER_RING] field of the RASID special
- * register, which is the current user-task asid allocation value.
- * mm->context has the same meaning.  When it comes time to write the
- * asid_cache or mm->context values to the RASID special register, we first
- * shift the value left by 8, then insert the value.
- * ASID[0] always contains the kernel's asid value, and we reserve three
- * other asid values that we never assign to user tasks.
- */
-
-#define ASID_INC       0x1
-#define ASID_MASK      ((1 << XCHAL_MMU_ASID_BITS) - 1)
-
-/*
- * XCHAL_MMU_ASID_INVALID is a configurable Xtensa processor constant
- * indicating invalid address space.  XCHAL_MMU_ASID_KERNEL is a configurable
- * Xtensa processor constant indicating the kernel address space.  They can
- * be arbitrary values.
- *
- * We identify three more unique, reserved ASID values to use in the unused
- * ring positions.  No other user process will be assigned these reserved
- * ASID values.
- *
- * For example, given that
- *
- *     XCHAL_MMU_ASID_INVALID == 0
- *     XCHAL_MMU_ASID_KERNEL  == 1
- *
- * the following maze of #if statements would generate
- *
- *     ASID_RESERVED_1        == 2
- *     ASID_RESERVED_2        == 3
- *     ASID_RESERVED_3        == 4
- *     ASID_FIRST_NONRESERVED == 5
- */
-
-#if (XCHAL_MMU_ASID_INVALID != XCHAL_MMU_ASID_KERNEL + 1)
-# define ASID_RESERVED_1         ((XCHAL_MMU_ASID_KERNEL + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_1         ((XCHAL_MMU_ASID_KERNEL + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_1 + 1)
-# define ASID_RESERVED_2         ((ASID_RESERVED_1 + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_2         ((ASID_RESERVED_1 + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_2 + 1)
-# define ASID_RESERVED_3         ((ASID_RESERVED_2 + 1) & ASID_MASK)
-#else
-# define ASID_RESERVED_3         ((ASID_RESERVED_2 + 2) & ASID_MASK)
-#endif
-
-#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_3 + 1)
-# define ASID_FIRST_NONRESERVED  ((ASID_RESERVED_3 + 1) & ASID_MASK)
-#else
-# define ASID_FIRST_NONRESERVED  ((ASID_RESERVED_3 + 2) & ASID_MASK)
-#endif
-
-#define ASID_ALL_RESERVED ( ((ASID_RESERVED_1) << 24) + \
-                            ((ASID_RESERVED_2) << 16) + \
-                            ((ASID_RESERVED_3) <<  8) + \
-                            ((XCHAL_MMU_ASID_KERNEL))   )
-
 
 /*
  * NO_CONTEXT is the invalid ASID value that we don't ever assign to
- * any user or kernel context.  NO_CONTEXT is a better mnemonic than
- * XCHAL_MMU_ASID_INVALID, so we use it in code instead.
- */
-
-#define NO_CONTEXT   XCHAL_MMU_ASID_INVALID
-
-#if (KERNEL_RING != 0)
-# error The KERNEL_RING really should be zero.
-#endif
-
-#if (USER_RING >= XCHAL_MMU_RINGS)
-# error USER_RING cannot be greater than the highest numbered ring.
-#endif
-
-#if (USER_RING == KERNEL_RING)
-# error The user and kernel rings really should not be equal.
-#endif
-
-#if (USER_RING == 1)
-#define ASID_INSERT(x) ( ((ASID_RESERVED_1)   << 24) + \
-                         ((ASID_RESERVED_2)   << 16) + \
-                         (((x) & (ASID_MASK)) <<  8) + \
-                         ((XCHAL_MMU_ASID_KERNEL))   )
-
-#elif (USER_RING == 2)
-#define ASID_INSERT(x) ( ((ASID_RESERVED_1)   << 24) + \
-                         (((x) & (ASID_MASK)) << 16) + \
-                         ((ASID_RESERVED_2)   <<  8) + \
-                         ((XCHAL_MMU_ASID_KERNEL))   )
-
-#elif (USER_RING == 3)
-#define ASID_INSERT(x) ( (((x) & (ASID_MASK)) << 24) + \
-                        ((ASID_RESERVED_1)   << 16) + \
-                         ((ASID_RESERVED_2)   <<  8) + \
-                         ((XCHAL_MMU_ASID_KERNEL))   )
-
-#else
-#error Goofy value for USER_RING
-
-#endif /* USER_RING == 1 */
-
-
-/*
- *  All unused by hardware upper bits will be considered
- *  as a software asid extension.
+ * any user or kernel context.
+ *
+ * 0 invalid
+ * 1 kernel
+ * 2 reserved
+ * 3 reserved
+ * 4...255 available
  */
 
-#define ASID_VERSION_MASK  ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
-#define ASID_FIRST_VERSION                                             \
-       ((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
+#define NO_CONTEXT     0
+#define ASID_USER_FIRST        4
+#define ASID_MASK      ((1 << XCHAL_MMU_ASID_BITS) - 1)
+#define ASID_INSERT(x) (0x03020001 | (((x) & ASID_MASK) << 8))
 
 static inline void set_rasid_register (unsigned long val)
 {
@@ -207,67 +52,28 @@ static inline void set_rasid_register (unsigned long val)
 static inline unsigned long get_rasid_register (void)
 {
        unsigned long tmp;
-       __asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
+       __asm__ __volatile__ (" rsr %0,"__stringify(RASID)"\n\t" : "=a" (tmp));
        return tmp;
 }
 
-
-#if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
-
 static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+__get_new_mmu_context(struct mm_struct *mm)
 {
        extern void flush_tlb_all(void);
-       if (! ((asid += ASID_INC) & ASID_MASK) ) {
+       if (! (++asid_cache & ASID_MASK) ) {
                flush_tlb_all(); /* start new asid cycle */
-               if (!asid)      /* fix version if needed */
-                       asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
-               asid += ASID_FIRST_NONRESERVED;
+               asid_cache += ASID_USER_FIRST;
        }
-       mm->context = asid_cache = asid;
-}
-
-#else
-#warning ASID_{INVALID,KERNEL} values impose non-optimal get_new_mmu_context implementation
-
-/* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
-   really the best, but if you insist... */
-
-static inline int validate_asid (unsigned long asid)
-{
-       switch (asid) {
-       case XCHAL_MMU_ASID_INVALID:
-       case XCHAL_MMU_ASID_KERNEL:
-       case ASID_RESERVED_1:
-       case ASID_RESERVED_2:
-       case ASID_RESERVED_3:
-               return 0; /* can't use these values as ASIDs */
-       }
-       return 1; /* valid */
+       mm->context = asid_cache;
 }
 
 static inline void
-get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+__load_mmu_context(struct mm_struct *mm)
 {
-       extern void flush_tlb_all(void);
-       while (1) {
-               asid += ASID_INC;
-               if ( ! (asid & ASID_MASK) ) {
-                       flush_tlb_all(); /* start new asid cycle */
-                       if (!asid)      /* fix version if needed */
-                               asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
-                       asid += ASID_FIRST_NONRESERVED;
-                       break; /* no need to validate here */
-               }
-               if (validate_asid (asid & ASID_MASK))
-                       break;
-       }
-       mm->context = asid_cache = asid;
+       set_rasid_register(ASID_INSERT(mm->context));
+       invalidate_page_directory();
 }
 
-#endif
-
-
 /*
  * Initialize the context related info for a new mm_struct
  * instance.
@@ -280,6 +86,20 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
        return 0;
 }
 
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static inline void
+activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+       /* Unconditionally get a new ASID.  */
+
+       __get_new_mmu_context(next);
+       __load_mmu_context(next);
+}
+
+
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                              struct task_struct *tsk)
 {
@@ -287,11 +107,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 
        /* Check if our ASID is of an older version and thus invalid */
 
-       if ((next->context ^ asid) & ASID_VERSION_MASK)
-               get_new_mmu_context(next, asid);
+       if (next->context == NO_CONTEXT || ((next->context^asid) & ~ASID_MASK))
+               __get_new_mmu_context(next);
 
-       set_rasid_register (ASID_INSERT(next->context));
-       invalidate_page_directory();
+       __load_mmu_context(next);
 }
 
 #define deactivate_mm(tsk, mm) do { } while(0)
@@ -302,20 +121,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  */
 static inline void destroy_context(struct mm_struct *mm)
 {
-       /* Nothing to do. */
-}
-
-/*
- * After we have set current->mm to a new value, this activates
- * the context for the new mm so we see the new mappings.
- */
-static inline void
-activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-       /* Unconditionally get a new ASID.  */
-
-       get_new_mmu_context(next, asid_cache);
-       set_rasid_register (ASID_INSERT(next->context));
        invalidate_page_directory();
 }
 
index 40f4c6c3f580fd830706e21d9405235a38801d92..c631d006194b476db9d4f307a3e034f20625aa60 100644 (file)
 
 #include <asm/processor.h>
 
+#define XCHAL_KSEG_CACHED_VADDR 0xd0000000
+#define XCHAL_KSEG_BYPASS_VADDR 0xd8000000
+#define XCHAL_KSEG_PADDR        0x00000000
+#define XCHAL_KSEG_SIZE         0x08000000
+
 /*
  * PAGE_SHIFT determines the page size
  * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
  */
 
-#define PAGE_SHIFT             XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SHIFT             12
 #define PAGE_SIZE              (1 << PAGE_SHIFT)
 #define PAGE_MASK              (~(PAGE_SIZE-1))
 #define PAGE_ALIGN(addr)       (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
 
-#define DCACHE_WAY_SIZE                (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
 #define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
+#define MAX_MEM_PFN             XCHAL_KSEG_SIZE
+#define PGTABLE_START           0x80000000
 
 #ifdef __ASSEMBLY__
 
index c0eec8260b0eb19253099c8e311b78b593b8c33c..6f281392e3f854fc0589b104f9d188f3c4210e3a 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_PARAM_H
 #define _XTENSA_PARAM_H
 
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
 #ifdef __KERNEL__
 # define HZ            100             /* internal timer frequency */
index b4318934b10dfb0fd269bf7a5c918a19cad97d5c..2d4b5db6ea6340406c62e99be1bc1398daa5770d 100644 (file)
 #include <asm-generic/pgtable-nopmd.h>
 #include <asm/page.h>
 
-/* Assertions. */
-
-#ifdef CONFIG_MMU
-
-
-#if (XCHAL_MMU_RINGS < 2)
-# error Linux build assumes at least 2 ring levels.
-#endif
-
-#if (XCHAL_MMU_CA_BITS != 4)
-# error We assume exactly four bits for CA.
-#endif
-
-#if (XCHAL_MMU_SR_BITS != 0)
-# error We have no room for SR bits.
-#endif
-
-/*
- * Use the first min-wired way for mapping page-table pages.
- * Page coloring requires a second min-wired way.
- */
-
-#if (XCHAL_DTLB_MINWIRED_SETS == 0)
-# error Need a min-wired way for mapping page-table pages
-#endif
-
-#define DTLB_WAY_PGTABLE XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAY)
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
-# if XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAYS) >= 2
-#  define DTLB_WAY_DCACHE_ALIAS0 (DTLB_WAY_PGTABLE + 1)
-#  define DTLB_WAY_DCACHE_ALIAS1 (DTLB_WAY_PGTABLE + 2)
-# else
-#  error Page coloring requires its own wired dtlb way!
-# endif
-#endif
-
-#endif /* CONFIG_MMU */
-
 /*
  * We only use two ring levels, user and kernel space.
  */
@@ -97,7 +58,7 @@
 #define PGD_ORDER              0
 #define PMD_ORDER              0
 #define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
-#define FIRST_USER_ADDRESS      XCHAL_SEG_MAPPABLE_VADDR
+#define FIRST_USER_ADDRESS      0
 #define FIRST_USER_PGD_NR      (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
 
 /* virtual memory area. We keep a distance to other memory regions to be
index 22240f0018037b0ca1fb468fad634f7a49decdc6..6930c12adc1678344dd90541538eb90cb883ca97 100644 (file)
  * This file contains the default configuration of ISS.
  */
 
-#ifndef __ASM_XTENSA_ISS_HARDWARE
-#define __ASM_XTENSA_ISS_HARDWARE
+#ifndef _XTENSA_PLATFORM_ISS_HARDWARE_H
+#define _XTENSA_PLATFORM_ISS_HARDWARE_H
 
 /*
  * Memory configuration.
  */
 
-#define PLATFORM_DEFAULT_MEM_START XSHAL_RAM_PADDR
-#define PLATFORM_DEFAULT_MEM_SIZE XSHAL_RAM_VSIZE
+#define PLATFORM_DEFAULT_MEM_START     0x00000000
+#define PLATFORM_DEFAULT_MEM_SIZE      0x08000000
 
 /*
  * Interrupt configuration.
  */
 
-#endif /* __ASM_XTENSA_ISS_HARDWARE */
+#endif /* _XTENSA_PLATFORM_ISS_HARDWARE_H */
diff --git a/include/asm-xtensa/platform-iss/simcall.h b/include/asm-xtensa/platform-iss/simcall.h
new file mode 100644 (file)
index 0000000..6acb572
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * include/asm-xtensa/platform-iss/hardware.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2001 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_H
+#define _XTENSA_PLATFORM_ISS_SIMCALL_H
+
+
+/*
+ *  System call like services offered by the simulator host.
+ */
+
+#define SYS_nop                0       /* unused */
+#define SYS_exit       1       /*x*/
+#define SYS_fork       2
+#define SYS_read       3       /*x*/
+#define SYS_write      4       /*x*/
+#define SYS_open       5       /*x*/
+#define SYS_close      6       /*x*/
+#define SYS_rename     7       /*x 38 - waitpid */
+#define SYS_creat      8       /*x*/
+#define SYS_link       9       /*x (not implemented on WIN32) */
+#define SYS_unlink     10      /*x*/
+#define SYS_execv      11      /* n/a - execve */
+#define SYS_execve     12      /* 11 - chdir */
+#define SYS_pipe       13      /* 42 - time */
+#define SYS_stat       14      /* 106 - mknod */
+#define SYS_chmod      15
+#define SYS_chown      16      /* 202 - lchown */
+#define SYS_utime      17      /* 30 - break */
+#define SYS_wait       18      /* n/a - oldstat */
+#define SYS_lseek      19      /*x*/
+#define SYS_getpid     20
+#define SYS_isatty     21      /* n/a - mount */
+#define SYS_fstat      22      /* 108 - oldumount */
+#define SYS_time       23      /* 13 - setuid */
+#define SYS_gettimeofday 24    /*x 78 - getuid (not implemented on WIN32) */
+#define SYS_times      25      /*X 43 - stime (Xtensa-specific implementation) */
+#define SYS_socket      26
+#define SYS_sendto      27
+#define SYS_recvfrom    28
+#define SYS_select_one  29      /* not compitible select, one file descriptor at the time */
+#define SYS_bind        30
+#define SYS_ioctl      31
+
+/*
+ * SYS_select_one specifiers
+ */
+
+#define  XTISS_SELECT_ONE_READ    1
+#define  XTISS_SELECT_ONE_WRITE   2
+#define  XTISS_SELECT_ONE_EXCEPT  3
+
+
+#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */
+
index 2c816b0e77628d50d8af0a401cdaaf7a38b9406e..3470b44c12ceaf4c82aabbae4ac812fd4c16959d 100644 (file)
@@ -21,7 +21,7 @@
 
 typedef unsigned long  __kernel_ino_t;
 typedef unsigned int   __kernel_mode_t;
-typedef unsigned short __kernel_nlink_t;
+typedef unsigned long  __kernel_nlink_t;
 typedef long           __kernel_off_t;
 typedef int            __kernel_pid_t;
 typedef unsigned short __kernel_ipc_pid_t;
index 8b96e77c9d829c6c2bd92fbe2c15b1616ade29f2..4feb9f7f35a6414bc238a154f35ced888f353005 100644 (file)
 #ifndef _XTENSA_PROCESSOR_H
 #define _XTENSA_PROCESSOR_H
 
-#ifdef __ASSEMBLY__
-#define _ASMLANGUAGE
-#endif
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/specreg.h>
-#include <xtensa/config/tie.h>
-#include <xtensa/config/system.h>
+#include <asm/variant/core.h>
+#include <asm/coprocessor.h>
 
 #include <linux/compiler.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
-#include <asm/coprocessor.h>
+#include <asm/regs.h>
 
 /* Assertions. */
 
 #if (XCHAL_HAVE_WINDOWED != 1)
-#error Linux requires the Xtensa Windowed Registers Option.
+# error Linux requires the Xtensa Windowed Registers Option.
 #endif
 
 /*
@@ -145,11 +139,11 @@ struct thread_struct {
  * Note: We set-up ps as if we did a call4 to the new pc.
  *       set_thread_state in signal.c depends on it.
  */
-#define USER_PS_VALUE ( (1 << XCHAL_PS_WOE_SHIFT) + \
-                        (1 << XCHAL_PS_CALLINC_SHIFT) + \
-                        (USER_RING << XCHAL_PS_RING_SHIFT) + \
-                        (1 << XCHAL_PS_PROGSTACK_SHIFT) + \
-                        (1 << XCHAL_PS_EXCM_SHIFT) )
+#define USER_PS_VALUE ((1 << PS_WOE_BIT) |                             \
+                       (1 << PS_CALLINC_SHIFT) |                       \
+                       (USER_RING << PS_RING_SHIFT) |                  \
+                       (1 << PS_UM_BIT) |                              \
+                       (1 << PS_EXCM_BIT))
 
 /* Clearing a0 terminates the backtrace. */
 #define start_thread(regs, new_pc, new_sp) \
index a5ac71a5205c268cd9cc51bbe4e82d31f6444137..1b7fe363fad1ea4dda17622cab04471ba5f344a4 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_PTRACE_H
 #define _XTENSA_PTRACE_H
 
-#include <xtensa/config/core.h>
+#include <asm/variant/core.h>
 
 /*
  * Kernel stack
diff --git a/include/asm-xtensa/regs.h b/include/asm-xtensa/regs.h
new file mode 100644 (file)
index 0000000..c913d25
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006 Tensilica, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+#ifndef _XTENSA_REGS_H
+#define _XTENSA_REGS_H
+
+/*  Special registers.  */
+
+#define LBEG           0
+#define LEND           1
+#define LCOUNT         2
+#define SAR            3
+#define BR             4
+#define SCOMPARE1      12
+#define ACCHI          16
+#define ACCLO          17
+#define MR             32
+#define WINDOWBASE     72
+#define WINDOWSTART    73
+#define PTEVADDR       83
+#define RASID          90
+#define ITLBCFG                91
+#define DTLBCFG                92
+#define IBREAKENABLE   96
+#define DDR            104
+#define IBREAKA                128
+#define DBREAKA                144
+#define DBREAKC                160
+#define EPC            176
+#define EPC_1          177
+#define DEPC           192
+#define EPS            192
+#define EPS_1          193
+#define EXCSAVE                208
+#define EXCSAVE_1      209
+#define INTERRUPT      226
+#define INTENABLE      228
+#define PS             230
+#define THREADPTR      231
+#define EXCCAUSE       232
+#define DEBUGCAUSE     233
+#define CCOUNT         234
+#define PRID           235
+#define ICOUNT         236
+#define ICOUNTLEVEL    237
+#define EXCVADDR       238
+#define CCOMPARE       240
+#define MISC           244
+
+/*  Special names for read-only and write-only interrupt registers.  */
+
+#define INTREAD                226
+#define INTSET         226
+#define INTCLEAR       227
+
+/*  EXCCAUSE register fields  */
+
+#define EXCCAUSE_EXCCAUSE_SHIFT        0
+#define EXCCAUSE_EXCCAUSE_MASK 0x3F
+
+#define EXCCAUSE_ILLEGAL_INSTRUCTION           0
+#define EXCCAUSE_SYSTEM_CALL                   1
+#define EXCCAUSE_INSTRUCTION_FETCH_ERROR       2
+#define EXCCAUSE_LOAD_STORE_ERROR              3
+#define EXCCAUSE_LEVEL1_INTERRUPT              4
+#define EXCCAUSE_ALLOCA                                5
+#define EXCCAUSE_INTEGER_DIVIDE_BY_ZERO                6
+#define EXCCAUSE_SPECULATION                   7
+#define EXCCAUSE_PRIVILEGED                    8
+#define EXCCAUSE_UNALIGNED                     9
+#define EXCCAUSE_ITLB_MISS                     16
+#define EXCCAUSE_ITLB_MULTIHIT                 17
+#define EXCCAUSE_ITLB_PRIVILEGE                        18
+#define EXCCAUSE_ITLB_SIZE_RESTRICTION         19
+#define EXCCAUSE_FETCH_CACHE_ATTRIBUTE         20
+#define EXCCAUSE_DTLB_MISS                     24
+#define EXCCAUSE_DTLB_MULTIHIT                 25
+#define EXCCAUSE_DTLB_PRIVILEGE                        26
+#define EXCCAUSE_DTLB_SIZE_RESTRICTION         27
+#define EXCCAUSE_LOAD_CACHE_ATTRIBUTE          28
+#define EXCCAUSE_STORE_CACHE_ATTRIBUTE         29
+#define EXCCAUSE_FLOATING_POINT                        40
+
+/*  PS register fields.  */
+
+#define PS_WOE_BIT             18
+#define PS_CALLINC_SHIFT       16
+#define PS_CALLINC_MASK                0x00030000
+#define PS_OWB_SHIFT           8
+#define PS_OWB_MASK            0x00000F00
+#define PS_RING_SHIFT          6
+#define PS_RING_MASK           0x000000C0
+#define PS_UM_BIT              5
+#define PS_EXCM_BIT            4
+#define PS_INTLEVEL_SHIFT      0
+#define PS_INTLEVEL_MASK       0x0000000F
+
+/*  DBREAKCn register fields.  */
+
+#define DBREAKC_MASK_BIT               0
+#define DBREAKC_MASK_MASK              0x0000003F
+#define DBREAKC_LOAD_BIT               30
+#define DBREAKC_LOAD_MASK              0x40000000
+#define DBREAKC_STOR_BIT               31
+#define DBREAKC_STOR_MASK              0x80000000
+
+/*  DEBUGCAUSE register fields.  */
+
+#define DEBUGCAUSE_DEBUGINT_BIT                5       /* External debug interrupt */
+#define DEBUGCAUSE_BREAKN_BIT          4       /* BREAK.N instruction */
+#define DEBUGCAUSE_BREAK_BIT           3       /* BREAK instruction */
+#define DEBUGCAUSE_DBREAK_BIT          2       /* DBREAK match */
+#define DEBUGCAUSE_IBREAK_BIT          1       /* IBREAK match */
+#define DEBUGCAUSE_ICOUNT_BIT          0       /* ICOUNT would incr. to zero */
+
+#endif /* _XTENSA_SPECREG_H */
+
index 2d26c47666fe094207f9b6e906ad7de78829e5f1..c15870493b33e9610275d8af0785992275e95c28 100644 (file)
@@ -25,7 +25,7 @@
 
 struct semid64_ds {
        struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
-#if XCHAL_HAVE_LE
+#ifdef __XTENSA_EL__
        __kernel_time_t sem_otime;              /* last semop time */
        unsigned long   __unused1;
        __kernel_time_t sem_ctime;              /* last change time */
index a30b81a4b9337c08e745907e9387e7f3d1f6e820..ad4b0121782c90535d19655564e3d21d2292d65f 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef _XTENSA_SHMBUF_H
 #define _XTENSA_SHMBUF_H
 
+#if defined (__XTENSA_EL__)
 struct shmid64_ds {
        struct ipc64_perm       shm_perm;       /* operation perms */
        size_t                  shm_segsz;      /* size of segment (bytes) */
@@ -34,6 +35,26 @@ struct shmid64_ds {
        unsigned long           __unused4;
        unsigned long           __unused5;
 };
+#elif defined (__XTENSA_EB__)
+struct shmid64_ds {
+       struct ipc64_perm       shm_perm;       /* operation perms */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+       __kernel_time_t         shm_atime;      /* last attach time */
+       unsigned long           __unused1;
+       __kernel_time_t         shm_dtime;      /* last detach time */
+       unsigned long           __unused2;
+       __kernel_time_t         shm_ctime;      /* last change time */
+       unsigned long           __unused3;
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned long           shm_nattch;     /* no. of current attaches */
+       unsigned long           __unused4;
+       unsigned long           __unused5;
+};
+#else
+# error endian order not defined
+#endif
+
 
 struct shminfo64 {
        unsigned long   shmmax;
index 2f4662ff6c3aa1d7a99d2a9a3cfd3112e42ddc6e..149f4bce092f9f370cb87658617d1ecffc79ef1f 100644 (file)
 
 #include <linux/types.h>
 
-struct __old_kernel_stat {
-       unsigned short st_dev;
-       unsigned short st_ino;
-       unsigned short st_mode;
-       unsigned short st_nlink;
-       unsigned short st_uid;
-       unsigned short st_gid;
-       unsigned short st_rdev;
-       unsigned long  st_size;
-       unsigned long  st_atime;
-       unsigned long  st_mtime;
-       unsigned long  st_ctime;
-};
-
 #define STAT_HAVE_NSEC 1
 
 struct stat {
-       unsigned short st_dev;
-       unsigned short __pad1;
-       unsigned long st_ino;
-       unsigned short st_mode;
-       unsigned short st_nlink;
-       unsigned short st_uid;
-       unsigned short st_gid;
-       unsigned short st_rdev;
-       unsigned short __pad2;
-       unsigned long  st_size;
-       unsigned long  st_blksize;
-       unsigned long  st_blocks;
-       unsigned long  st_atime;
-       unsigned long  st_atime_nsec;
-       unsigned long  st_mtime;
-       unsigned long  st_mtime_nsec;
-       unsigned long  st_ctime;
-       unsigned long  st_ctime_nsec;
-       unsigned long  __unused4;
-       unsigned long  __unused5;
+       unsigned long   st_dev;
+       ino_t           st_ino;
+       mode_t          st_mode;
+       nlink_t         st_nlink;
+       uid_t           st_uid;
+       gid_t           st_gid;
+       unsigned int    st_rdev;
+       off_t           st_size;
+       unsigned long   st_blksize;
+       unsigned long   st_blocks;
+       unsigned long   st_atime;
+       unsigned long   st_atime_nsec;
+       unsigned long   st_mtime;
+       unsigned long   st_mtime_nsec;
+       unsigned long   st_ctime;
+       unsigned long   st_ctime_nsec;
+       unsigned long   __unused4;
+       unsigned long   __unused5;
 };
 
-/* This matches struct stat64 in glibc-2.2.3. */
+/* This matches struct stat64 in glibc-2.3 */
 
 struct stat64  {
-#ifdef __XTENSA_EL__
-       unsigned short  st_dev;         /* Device */
-       unsigned char   __pad0[10];
-#else
-       unsigned char   __pad0[6];
-       unsigned short  st_dev;
-       unsigned char   __pad1[2];
-#endif
-
-#define STAT64_HAS_BROKEN_ST_INO       1
-       unsigned long __st_ino;         /* 32bit file serial number. */
-
+       unsigned long long st_dev;      /* Device */
+       unsigned long long st_ino;      /* File serial number */
        unsigned int  st_mode;          /* File mode. */
        unsigned int  st_nlink;         /* Link count. */
        unsigned int  st_uid;           /* User ID of the file's owner. */
        unsigned int  st_gid;           /* Group ID of the file's group. */
-
-#ifdef __XTENSA_EL__
-       unsigned short  st_rdev;        /* Device number, if device. */
-       unsigned char   __pad3[10];
-#else
-       unsigned char   __pad2[6];
-       unsigned short  st_rdev;
-       unsigned char   __pad3[2];
-#endif
-
-       long long int  st_size;         /* Size of file, in bytes. */
-       long int st_blksize;            /* Optimal block size for I/O. */
-
-#ifdef __XTENSA_EL__
-       unsigned long  st_blocks;       /* Number 512-byte blocks allocated. */
-       unsigned long  __pad4;
+       unsigned long long st_rdev;     /* Device number, if device. */
+       long long st_size;              /* Size of file, in bytes. */
+       long st_blksize;                /* Optimal block size for I/O. */
+       unsigned long __unused2;
+#ifdef __XTENSA_EB__
+       unsigned long __unused3;
+       long st_blocks;                 /* Number 512-byte blocks allocated. */
 #else
-       unsigned long  __pad4;
-       unsigned long  st_blocks;
+       long st_blocks;                 /* Number 512-byte blocks allocated. */
+       unsigned long __unused3;
 #endif
-
-       unsigned long  __pad5;
-       long int st_atime;              /* Time of last access. */
-       unsigned long  st_atime_nsec;
-       long int st_mtime;              /* Time of last modification. */
-       unsigned long  st_mtime_nsec;
-       long int  st_ctime;             /* Time of last status change. */
-       unsigned long  st_ctime_nsec;
-       unsigned long long int st_ino;  /* File serial number. */
+       long st_atime;                  /* Time of last access. */
+       unsigned long st_atime_nsec;
+       long st_mtime;                  /* Time of last modification. */
+       unsigned long st_mtime_nsec;
+       long st_ctime;                  /* Time of last status change. */
+       unsigned long st_ctime_nsec;
+       unsigned long __unused4;
+       unsigned long __unused5;
 };
 
 #endif /* _XTENSA_STAT_H */
diff --git a/include/asm-xtensa/syscall.h b/include/asm-xtensa/syscall.h
new file mode 100644 (file)
index 0000000..6cb0d42
--- /dev/null
@@ -0,0 +1,20 @@
+struct pt_regs;
+struct sigaction;
+asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
+asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
+asmlinkage long xtensa_pipe(int __user *);
+asmlinkage long xtensa_mmap2(unsigned long, unsigned long, unsigned long,
+                            unsigned long, unsigned long, unsigned long);
+asmlinkage long xtensa_ptrace(long, long, long, long);
+asmlinkage long xtensa_sigreturn(struct pt_regs*);
+asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
+asmlinkage long xtensa_sigsuspend(struct pt_regs*);
+asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*);
+asmlinkage long xtensa_sigaction(int, const struct old_sigaction*,
+                                struct old_sigaction*);
+asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
+asmlinkage long sys_rt_sigaction(int,
+                                const struct sigaction __user *,
+                                struct sigaction __user *,
+                                size_t);
+asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg);
index 932bda92a21c392b609e67eb09608897d4259657..4aaed7fe6cfee3964531029a4013a0996888320b 100644 (file)
@@ -213,7 +213,7 @@ static inline void spill_registers(void)
        unsigned int a0, ps;
 
        __asm__ __volatile__ (
-               "movi   a14," __stringify (PS_EXCM_MASK) " | 1\n\t"
+               "movi   a14," __stringify (PS_EXCM_BIT) " | 1\n\t"
                "mov    a12, a0\n\t"
                "rsr    a13," __stringify(SAR) "\n\t"
                "xsr    a14," __stringify(PS) "\n\t"
index c7b705e66655746a2efce6fdeefbd76f128d0acd..28c7985a40006b5001f693d94e19b9ca9e09283b 100644 (file)
 #include <asm/processor.h>
 #include <linux/stringify.h>
 
-#if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1
+#define _INTLEVEL(x)   XCHAL_INT ## x ## _LEVEL
+#define INTLEVEL(x)    _INTLEVEL(x)
+
+#if INTLEVEL(XCHAL_TIMER0_INTERRUPT) == 1
 # define LINUX_TIMER     0
-#elif XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1
+# define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT
+#elif INTLEVEL(XCHAL_TIMER1_INTERRUPT) == 1
 # define LINUX_TIMER     1
-#elif XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1
+# define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT
+#elif INTLEVEL(XCHAL_TIMER2_INTERRUPT) == 1
 # define LINUX_TIMER     2
+# define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT
 #else
 # error "Bad timer number for Linux configurations!"
 #endif
 
-#define LINUX_TIMER_INT         XCHAL_TIMER_INTERRUPT(LINUX_TIMER)
 #define LINUX_TIMER_MASK        (1L << LINUX_TIMER_INT)
 
 #define CLOCK_TICK_RATE        1193180 /* (everyone is using this value) */
@@ -60,8 +65,8 @@ extern cycles_t cacheflush_time;
 
 #define WSR_CCOUNT(r)    __asm__("wsr %0,"__stringify(CCOUNT) :: "a" (r))
 #define RSR_CCOUNT(r)    __asm__("rsr %0,"__stringify(CCOUNT) : "=a" (r))
-#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) :: "a"(r))
-#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) : "=a"(r))
+#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE)"+"__stringify(x) :: "a"(r))
+#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE)"+"__stringify(x) : "=a"(r))
 
 static inline unsigned long get_ccount (void)
 {
index 43f6ec859af92fccd699bcc918f01a3467fa63d4..7c637b3c352cf0fcae1a903057e17ee30567d7c0 100644 (file)
 #ifndef _XTENSA_TLBFLUSH_H
 #define _XTENSA_TLBFLUSH_H
 
-#define DEBUG_TLB
-
 #ifdef __KERNEL__
 
-#include <asm/processor.h>
 #include <linux/stringify.h>
+#include <asm/processor.h>
+
+#define DTLB_WAY_PGD   7
+
+#define ITLB_ARF_WAYS  4
+#define DTLB_ARF_WAYS  4
+
+#define ITLB_HIT_BIT   3
+#define DTLB_HIT_BIT   4
+
+#ifndef __ASSEMBLY__
 
 /* TLB flushing:
  *
@@ -46,11 +54,6 @@ static inline void flush_tlb_pgtables(struct mm_struct *mm,
 
 /* TLB operations. */
 
-#define ITLB_WAYS_LOG2      XCHAL_ITLB_WAY_BITS
-#define DTLB_WAYS_LOG2      XCHAL_DTLB_WAY_BITS
-#define ITLB_PROBE_SUCCESS  (1 << ITLB_WAYS_LOG2)
-#define DTLB_PROBE_SUCCESS  (1 << DTLB_WAYS_LOG2)
-
 static inline unsigned long itlb_probe(unsigned long addr)
 {
        unsigned long tmp;
@@ -131,29 +134,30 @@ static inline void write_itlb_entry (pte_t entry, int way)
 
 static inline void invalidate_page_directory (void)
 {
-       invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
+       invalidate_dtlb_entry (DTLB_WAY_PGD);
+       invalidate_dtlb_entry (DTLB_WAY_PGD+1);
+       invalidate_dtlb_entry (DTLB_WAY_PGD+2);
 }
 
 static inline void invalidate_itlb_mapping (unsigned address)
 {
        unsigned long tlb_entry;
-       while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
-               invalidate_itlb_entry (tlb_entry);
+       if (((tlb_entry = itlb_probe(address)) & (1 << ITLB_HIT_BIT)) != 0)
+               invalidate_itlb_entry(tlb_entry);
 }
 
 static inline void invalidate_dtlb_mapping (unsigned address)
 {
        unsigned long tlb_entry;
-       while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
-               invalidate_dtlb_entry (tlb_entry);
+       if (((tlb_entry = dtlb_probe(address)) & (1 << DTLB_HIT_BIT)) != 0)
+               invalidate_dtlb_entry(tlb_entry);
 }
 
 #define check_pgt_cache()      do { } while (0)
 
 
-#ifdef DEBUG_TLB
-
-/* DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
+/*
+ * DO NOT USE THESE FUNCTIONS.  These instructions aren't part of the Xtensa
  * ISA and exist only for test purposes..
  * You may find it helpful for MMU debugging, however.
  *
@@ -193,8 +197,6 @@ static inline unsigned long read_itlb_translation (int way)
        return tmp;
 }
 
-#endif /* DEBUG_TLB */
-
-
+#endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
-#endif /* _XTENSA_PGALLOC_H */
+#endif /* _XTENSA_TLBFLUSH_H */
index 2e1a1b997e7d7f89ede319c9029ec8ef90437458..8a7fb6964ce144319576ce856cfd4d16284abf68 100644 (file)
 #ifndef _XTENSA_UNISTD_H
 #define _XTENSA_UNISTD_H
 
-#define __NR_spill               0
-#define __NR_exit                1
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_lchown             16
-#define __NR_break              17
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_ptrace             26
-#define __NR_utime              30
-#define __NR_stty               31
-#define __NR_gtty               32
-#define __NR_access             33
-#define __NR_ftime              35
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-#define __NR_prof               44
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_signal             48
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_lock               53
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-#define __NR_setpgid            57
-#define __NR_ulimit             58
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_setsid             66
-#define __NR_sigaction          67
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_sigsuspend                 72
-#define __NR_sigpending                 73
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-#define __NR_getrlimit          76     /* Back compatible 2Gig limited rlimit */
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_select             82
-#define __NR_symlink            83
-#define __NR_readlink           85
-#define __NR_uselib             86
-#define __NR_swapon             87
-#define __NR_reboot             88
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-#define __NR_profil             98
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-#define __NR_ioperm            101
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-#define __NR_iopl              110
-#define __NR_vhangup           111
-#define __NR_idle              112
-#define __NR_wait4             114
-#define __NR_swapoff           115
-#define __NR_sysinfo           116
-#define __NR_fsync             118
-#define __NR_sigreturn         119
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-#define __NR_modify_ldt                123
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-#define __NR_create_module     127
-#define __NR_init_module       128
-#define __NR_delete_module     129
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-#define __NR_sysfs             135
-#define __NR_personality       136
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR_getdents          141
-#define __NR__newselect                142
-#define __NR_flock             143
-#define __NR_msync             144
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_cacheflush         147
-#define __NR_cachectl           148
-#define __NR_sysxtensa          149
-#define __NR_sysdummy           150
-#define __NR_getsid            151
-#define __NR_fdatasync         152
-#define __NR__sysctl           153
-#define __NR_mlock             154
-#define __NR_munlock           155
-#define __NR_mlockall          156
-#define __NR_munlockall                157
-#define __NR_sched_setparam            158
-#define __NR_sched_getparam            159
-#define __NR_sched_setscheduler                160
-#define __NR_sched_getscheduler                161
-#define __NR_sched_yield               162
-#define __NR_sched_get_priority_max    163
-#define __NR_sched_get_priority_min    164
-#define __NR_sched_rr_get_interval     165
-#define __NR_nanosleep         166
-#define __NR_mremap            167
-#define __NR_accept             168
-#define __NR_bind               169
-#define __NR_connect            170
-#define __NR_getpeername        171
-#define __NR_getsockname        172
-#define __NR_getsockopt         173
-#define __NR_listen             174
-#define __NR_recv               175
-#define __NR_recvfrom           176
-#define __NR_recvmsg            177
-#define __NR_send               178
-#define __NR_sendmsg            179
-#define __NR_sendto             180
-#define __NR_setsockopt         181
-#define __NR_shutdown           182
-#define __NR_socket             183
-#define __NR_socketpair         184
-#define __NR_setresuid         185
-#define __NR_getresuid         186
-#define __NR_query_module      187
-#define __NR_poll              188
-#define __NR_nfsservctl                189
-#define __NR_setresgid         190
-#define __NR_getresgid         191
-#define __NR_prctl              192
-#define __NR_rt_sigreturn      193
-#define __NR_rt_sigaction      194
-#define __NR_rt_sigprocmask    195
-#define __NR_rt_sigpending     196
-#define __NR_rt_sigtimedwait   197
-#define __NR_rt_sigqueueinfo   198
-#define __NR_rt_sigsuspend     199
-#define __NR_pread             200
-#define __NR_pwrite            201
-#define __NR_chown             202
-#define __NR_getcwd            203
-#define __NR_capget            204
-#define __NR_capset            205
-#define __NR_sigaltstack       206
-#define __NR_sendfile          207
-#define __NR_mmap2             210
-#define __NR_truncate64                211
-#define __NR_ftruncate64       212
-#define __NR_stat64            213
-#define __NR_lstat64           214
-#define __NR_fstat64           215
-#define __NR_pivot_root                216
-#define __NR_mincore           217
-#define __NR_madvise           218
-#define __NR_getdents64                219
-
-/* Keep this last; should always equal the last valid call number. */
-#define __NR_Linux_syscalls     220
-
-/* user-visible error numbers are in the range -1 - -125: see
- * <asm-xtensa/errno.h> */
-
-#define SYSXTENSA_RESERVED        0    /* don't use this */
-#define SYSXTENSA_ATOMIC_SET      1    /* set variable */
-#define SYSXTENSA_ATOMIC_EXG_ADD   2   /* exchange memory and add */
-#define SYSXTENSA_ATOMIC_ADD      3    /* add to memory */
-#define SYSXTENSA_ATOMIC_CMP_SWP   4   /* compare and swap */
-
-#define SYSXTENSA_COUNT                   5    /* count of syscall0 functions*/
+#ifndef __SYSCALL
+# define __SYSCALL(nr,func,nargs)
+#endif
+
+#define __NR_spill                               0
+__SYSCALL(  0, sys_ni_syscall, 0)
+#define __NR_xtensa                              1
+__SYSCALL(  1, sys_ni_syscall, 0)
+#define __NR_available4                                  2
+__SYSCALL(  2, sys_ni_syscall, 0)
+#define __NR_available5                                  3
+__SYSCALL(  3, sys_ni_syscall, 0)
+#define __NR_available6                                  4
+__SYSCALL(  4, sys_ni_syscall, 0)
+#define __NR_available7                                  5
+__SYSCALL(  5, sys_ni_syscall, 0)
+#define __NR_available8                                  6
+__SYSCALL(  6, sys_ni_syscall, 0)
+#define __NR_available9                                  7
+__SYSCALL(  7, sys_ni_syscall, 0)
+
+/* File Operations */
+
+#define __NR_open                                8
+__SYSCALL(  8, sys_open, 3)
+#define __NR_close                               9
+__SYSCALL(  9, sys_close, 1)
+#define __NR_dup                                10
+__SYSCALL( 10, sys_dup, 1)
+#define __NR_dup2                               11
+__SYSCALL( 11, sys_dup2, 2)
+#define __NR_read                               12
+__SYSCALL( 12, sys_read, 3)
+#define __NR_write                              13
+__SYSCALL( 13, sys_write, 3)
+#define __NR_select                             14
+__SYSCALL( 14, sys_select, 5)
+#define __NR_lseek                              15
+__SYSCALL( 15, sys_lseek, 3)
+#define __NR_poll                               16
+__SYSCALL( 16, sys_poll, 3)
+#define __NR__llseek                            17
+__SYSCALL( 17, sys_llseek, 5)
+#define __NR_epoll_wait                         18
+__SYSCALL( 18, sys_epoll_wait, 4)
+#define __NR_epoll_ctl                                  19
+__SYSCALL( 19, sys_epoll_ctl, 4)
+#define __NR_epoll_create                       20
+__SYSCALL( 20, sys_epoll_create, 1)
+#define __NR_creat                              21
+__SYSCALL( 21, sys_creat, 2)
+#define __NR_truncate                           22
+__SYSCALL( 22, sys_truncate, 2)
+#define __NR_ftruncate                                  23
+__SYSCALL( 23, sys_ftruncate, 2)
+#define __NR_readv                              24
+__SYSCALL( 24, sys_readv, 3)
+#define __NR_writev                             25
+__SYSCALL( 25, sys_writev, 3)
+#define __NR_fsync                              26
+__SYSCALL( 26, sys_fsync, 1)
+#define __NR_fdatasync                                  27
+__SYSCALL( 27, sys_fdatasync, 1)
+#define __NR_truncate64                         28
+__SYSCALL( 28, sys_truncate64, 2)
+#define __NR_ftruncate64                        29
+__SYSCALL( 29, sys_ftruncate64, 2)
+#define __NR_pread64                            30
+__SYSCALL( 30, sys_pread64, 6)
+#define __NR_pwrite64                           31
+__SYSCALL( 31, sys_pwrite64, 6)
+
+#define __NR_link                               32
+__SYSCALL( 32, sys_link, 2)
+#define __NR_rename                             33
+__SYSCALL( 33, sys_rename, 2)
+#define __NR_symlink                            34
+__SYSCALL( 34, sys_symlink, 2)
+#define __NR_readlink                           35
+__SYSCALL( 35, sys_readlink, 3)
+#define __NR_mknod                              36
+__SYSCALL( 36, sys_mknod, 3)
+#define __NR_pipe                               37
+__SYSCALL( 37, xtensa_pipe, 1)
+#define __NR_unlink                             38
+__SYSCALL( 38, sys_unlink, 1)
+#define __NR_rmdir                              39
+__SYSCALL( 39, sys_rmdir, 1)
+
+#define __NR_mkdir                              40
+__SYSCALL( 40, sys_mkdir, 2)
+#define __NR_chdir                              41
+__SYSCALL( 41, sys_chdir, 1)
+#define __NR_fchdir                             42
+__SYSCALL( 42, sys_fchdir, 1)
+#define __NR_getcwd                             43
+__SYSCALL( 43, sys_getcwd, 2)
+
+#define __NR_chmod                              44
+__SYSCALL( 44, sys_chmod, 2)
+#define __NR_chown                              45
+__SYSCALL( 45, sys_chown, 3)
+#define __NR_stat                               46
+__SYSCALL( 46, sys_newstat, 2)
+#define __NR_stat64                             47
+__SYSCALL( 47, sys_stat64, 2)
+
+#define __NR_lchown                             48
+__SYSCALL( 48, sys_lchown, 3)
+#define __NR_lstat                              49
+__SYSCALL( 49, sys_newlstat, 2)
+#define __NR_lstat64                            50
+__SYSCALL( 50, sys_lstat64, 2)
+#define __NR_available51                        51
+__SYSCALL( 51, sys_ni_syscall, 0)
+
+#define __NR_fchmod                             52
+__SYSCALL( 52, sys_fchmod, 2)
+#define __NR_fchown                             53
+__SYSCALL( 53, sys_fchown, 3)
+#define __NR_fstat                              54
+__SYSCALL( 54, sys_newfstat, 2)
+#define __NR_fstat64                            55
+__SYSCALL( 55, sys_fstat64, 2)
+
+#define __NR_flock                              56
+__SYSCALL( 56, sys_flock, 2)
+#define __NR_access                             57
+__SYSCALL( 57, sys_access, 2)
+#define __NR_umask                              58
+__SYSCALL( 58, sys_umask, 1)
+#define __NR_getdents                           59
+__SYSCALL( 59, sys_getdents, 3)
+#define __NR_getdents64                         60
+__SYSCALL( 60, sys_getdents64, 3)
+#define __NR_fcntl64                            61
+__SYSCALL( 61, sys_fcntl64, 3)
+#define __NR_available62                        62
+__SYSCALL( 62, sys_ni_syscall, 0)
+#define __NR_fadvise64_64                       63
+__SYSCALL( 63, sys_fadvise64_64, 6)
+#define __NR_utime                              64     /* glibc 2.3.3 ?? */
+__SYSCALL( 64, sys_utime, 2)
+#define __NR_utimes                             65
+__SYSCALL( 65, sys_utimes, 2)
+#define __NR_ioctl                              66
+__SYSCALL( 66, sys_ioctl, 3)
+#define __NR_fcntl                              67
+__SYSCALL( 67, sys_fcntl, 3)
+
+#define __NR_setxattr                           68
+__SYSCALL( 68, sys_setxattr, 5)
+#define __NR_getxattr                           69
+__SYSCALL( 69, sys_getxattr, 4)
+#define __NR_listxattr                                  70
+__SYSCALL( 70, sys_listxattr, 3)
+#define __NR_removexattr                        71
+__SYSCALL( 71, sys_removexattr, 2)
+#define __NR_lsetxattr                                  72
+__SYSCALL( 72, sys_lsetxattr, 5)
+#define __NR_lgetxattr                                  73
+__SYSCALL( 73, sys_lgetxattr, 4)
+#define __NR_llistxattr                         74
+__SYSCALL( 74, sys_llistxattr, 3)
+#define __NR_lremovexattr                       75
+__SYSCALL( 75, sys_lremovexattr, 2)
+#define __NR_fsetxattr                                  76
+__SYSCALL( 76, sys_fsetxattr, 5)
+#define __NR_fgetxattr                                  77
+__SYSCALL( 77, sys_fgetxattr, 4)
+#define __NR_flistxattr                         78
+__SYSCALL( 78, sys_flistxattr, 3)
+#define __NR_fremovexattr                       79
+__SYSCALL( 79, sys_fremovexattr, 2)
+
+/* File Map / Shared Memory Operations */
+
+#define __NR_mmap2                              80
+__SYSCALL( 80, xtensa_mmap2, 6)
+#define __NR_munmap                             81
+__SYSCALL( 81, sys_munmap, 2)
+#define __NR_mprotect                           82
+__SYSCALL( 82, sys_mprotect, 3)
+#define __NR_brk                                83
+__SYSCALL( 83, sys_brk, 1)
+#define __NR_mlock                              84
+__SYSCALL( 84, sys_mlock, 2)
+#define __NR_munlock                            85
+__SYSCALL( 85, sys_munlock, 2)
+#define __NR_mlockall                           86
+__SYSCALL( 86, sys_mlockall, 1)
+#define __NR_munlockall                         87
+__SYSCALL( 87, sys_munlockall, 0)
+#define __NR_mremap                             88
+__SYSCALL( 88, sys_mremap, 4)
+#define __NR_msync                              89
+__SYSCALL( 89, sys_msync, 3)
+#define __NR_mincore                            90
+__SYSCALL( 90, sys_mincore, 3)
+#define __NR_madvise                            91
+__SYSCALL( 91, sys_madvise, 3)
+#define __NR_shmget                             92
+__SYSCALL( 92, sys_shmget, 4)
+#define __NR_shmat                              93
+__SYSCALL( 93, xtensa_shmat, 4)
+#define __NR_shmctl                             94
+__SYSCALL( 94, sys_shmctl, 4)
+#define __NR_shmdt                              95
+__SYSCALL( 95, sys_shmdt, 4)
+
+/* Socket Operations */
+
+#define __NR_socket                             96
+__SYSCALL( 96, sys_socket, 3)
+#define __NR_setsockopt                         97
+__SYSCALL( 97, sys_setsockopt, 5)
+#define __NR_getsockopt                         98
+__SYSCALL( 98, sys_getsockopt, 5)
+#define __NR_shutdown                           99
+__SYSCALL( 99, sys_shutdown, 2)
+
+#define __NR_bind                              100
+__SYSCALL(100, sys_bind, 3)
+#define __NR_connect                           101
+__SYSCALL(101, sys_connect, 3)
+#define __NR_listen                            102
+__SYSCALL(102, sys_listen, 2)
+#define __NR_accept                            103
+__SYSCALL(103, sys_accept, 3)
+
+#define __NR_getsockname                       104
+__SYSCALL(104, sys_getsockname, 3)
+#define __NR_getpeername                       105
+__SYSCALL(105, sys_getpeername, 3)
+#define __NR_sendmsg                           106
+__SYSCALL(106, sys_sendmsg, 3)
+#define __NR_recvmsg                           107
+__SYSCALL(107, sys_recvmsg, 3)
+#define __NR_send                              108
+__SYSCALL(108, sys_send, 4)
+#define __NR_recv                              109
+__SYSCALL(109, sys_recv, 4)
+#define __NR_sendto                            110
+__SYSCALL(110, sys_sendto, 6)
+#define __NR_recvfrom                          111
+__SYSCALL(111, sys_recvfrom, 6)
+
+#define __NR_socketpair                        112
+__SYSCALL(112, sys_socketpair, 4)
+#define __NR_sendfile                          113
+__SYSCALL(113, sys_sendfile, 4)
+#define __NR_sendfile64                        114
+__SYSCALL(114, sys_sendfile64, 4)
+#define __NR_available115                      115
+__SYSCALL(115, sys_ni_syscall, 0)
+
+/* Process Operations */
+
+#define __NR_clone                             116
+__SYSCALL(116, xtensa_clone, 5)
+#define __NR_execve                            117
+__SYSCALL(117, xtensa_execve, 3)
+#define __NR_exit                              118
+__SYSCALL(118, sys_exit, 1)
+#define __NR_exit_group                        119
+__SYSCALL(119, sys_exit_group, 1)
+#define __NR_getpid                            120
+__SYSCALL(120, sys_getpid, 0)
+#define __NR_wait4                             121
+__SYSCALL(121, sys_wait4, 4)
+#define __NR_waitid                            122
+__SYSCALL(122, sys_waitid, 5)
+#define __NR_kill                              123
+__SYSCALL(123, sys_kill, 2)
+#define __NR_tkill                             124
+__SYSCALL(124, sys_tkill, 2)
+#define __NR_tgkill                            125
+__SYSCALL(125, sys_tgkill, 3)
+#define __NR_set_tid_address                   126
+__SYSCALL(126, sys_set_tid_address, 1)
+#define __NR_gettid                            127
+__SYSCALL(127, sys_gettid, 0)
+#define __NR_setsid                            128
+__SYSCALL(128, sys_setsid, 0)
+#define __NR_getsid                            129
+__SYSCALL(129, sys_getsid, 1)
+#define __NR_prctl                             130
+__SYSCALL(130, sys_prctl, 5)
+#define __NR_personality                       131
+__SYSCALL(131, sys_personality, 1)
+#define __NR_getpriority                       132
+__SYSCALL(132, sys_getpriority, 2)
+#define __NR_setpriority                       133
+__SYSCALL(133, sys_setpriority, 3)
+#define __NR_setitimer                                 134
+__SYSCALL(134, sys_setitimer, 3)
+#define __NR_getitimer                                 135
+__SYSCALL(135, sys_getitimer, 2)
+#define __NR_setuid                            136
+__SYSCALL(136, sys_setuid, 1)
+#define __NR_getuid                            137
+__SYSCALL(137, sys_getuid, 0)
+#define __NR_setgid                            138
+__SYSCALL(138, sys_setgid, 1)
+#define __NR_getgid                            139
+__SYSCALL(139, sys_getgid, 0)
+#define __NR_geteuid                           140
+__SYSCALL(140, sys_geteuid, 0)
+#define __NR_getegid                           141
+__SYSCALL(141, sys_getegid, 0)
+#define __NR_setreuid                          142
+__SYSCALL(142, sys_setreuid, 2)
+#define __NR_setregid                          143
+__SYSCALL(143, sys_setregid, 2)
+#define __NR_setresuid                                 144
+__SYSCALL(144, sys_setresuid, 3)
+#define __NR_getresuid                                 145
+__SYSCALL(145, sys_getresuid, 3)
+#define __NR_setresgid                                 146
+__SYSCALL(146, sys_setresgid, 3)
+#define __NR_getresgid                                 147
+__SYSCALL(147, sys_getresgid, 3)
+#define __NR_setpgid                           148
+__SYSCALL(148, sys_setpgid, 2)
+#define __NR_getpgid                           149
+__SYSCALL(149, sys_getpgid, 1)
+#define __NR_getppid                           150
+__SYSCALL(150, sys_getppid, 0)
+#define __NR_available151                      151
+__SYSCALL(151, sys_ni_syscall, 0)
+
+#define __NR_reserved152                       152     /* set_thread_area */
+__SYSCALL(152, sys_ni_syscall, 0)
+#define __NR_reserved153                       153     /* get_thread_area */
+__SYSCALL(153, sys_ni_syscall, 0)
+#define __NR_times                             154
+__SYSCALL(154, sys_times, 1)
+#define __NR_acct                              155
+__SYSCALL(155, sys_acct, 1)
+#define __NR_sched_setaffinity                         156
+__SYSCALL(156, sys_sched_setaffinity, 3)
+#define __NR_sched_getaffinity                         157
+__SYSCALL(157, sys_sched_getaffinity, 3)
+#define __NR_capget                            158
+__SYSCALL(158, sys_capget, 2)
+#define __NR_capset                            159
+__SYSCALL(159, sys_capset, 2)
+#define __NR_ptrace                            160
+__SYSCALL(160, sys_ptrace, 4)
+#define __NR_semtimedop                                161
+__SYSCALL(161, sys_semtimedop, 5)
+#define __NR_semget                            162
+__SYSCALL(162, sys_semget, 4)
+#define __NR_semop                             163
+__SYSCALL(163, sys_semop, 4)
+#define __NR_semctl                            164
+__SYSCALL(164, sys_semctl, 4)
+#define __NR_available165                      165
+__SYSCALL(165, sys_ni_syscall, 0)
+#define __NR_msgget                            166
+__SYSCALL(166, sys_msgget, 4)
+#define __NR_msgsnd                            167
+__SYSCALL(167, sys_msgsnd, 4)
+#define __NR_msgrcv                            168
+__SYSCALL(168, sys_msgrcv, 4)
+#define __NR_msgctl                            169
+__SYSCALL(169, sys_msgctl, 4)
+#define __NR_available170                      170
+__SYSCALL(170, sys_ni_syscall, 0)
+#define __NR_available171                      171
+__SYSCALL(171, sys_ni_syscall, 0)
+
+/* File System */
+
+#define __NR_mount                             172
+__SYSCALL(172, sys_mount, 5)
+#define __NR_swapon                            173
+__SYSCALL(173, sys_swapon, 2)
+#define __NR_chroot                            174
+__SYSCALL(174, sys_chroot, 1)
+#define __NR_pivot_root                        175
+__SYSCALL(175, sys_pivot_root, 2)
+#define __NR_umount                            176
+__SYSCALL(176, sys_umount, 2)
+#define __NR_swapoff                           177
+__SYSCALL(177, sys_swapoff, 1)
+#define __NR_sync                              178
+__SYSCALL(178, sys_sync, 0)
+#define __NR_available179                      179
+__SYSCALL(179, sys_ni_syscall, 0)
+#define __NR_setfsuid                          180
+__SYSCALL(180, sys_setfsuid, 1)
+#define __NR_setfsgid                          181
+__SYSCALL(181, sys_setfsgid, 1)
+#define __NR_sysfs                             182
+__SYSCALL(182, sys_sysfs, 3)
+#define __NR_ustat                             183
+__SYSCALL(183, sys_ustat, 2)
+#define __NR_statfs                            184
+__SYSCALL(184, sys_statfs, 2)
+#define __NR_fstatfs                           185
+__SYSCALL(185, sys_fstatfs, 2)
+#define __NR_statfs64                          186
+__SYSCALL(186, sys_statfs64, 3)
+#define __NR_fstatfs64                                 187
+__SYSCALL(187, sys_fstatfs64, 3)
+
+/* System */
+
+#define __NR_setrlimit                                 188
+__SYSCALL(188, sys_setrlimit, 2)
+#define __NR_getrlimit                                 189
+__SYSCALL(189, sys_getrlimit, 2)
+#define __NR_getrusage                                 190
+__SYSCALL(190, sys_getrusage, 2)
+#define __NR_futex                             191
+__SYSCALL(191, sys_futex, 5)
+#define __NR_gettimeofday                      192
+__SYSCALL(192, sys_gettimeofday, 2)
+#define __NR_settimeofday                      193
+__SYSCALL(193, sys_settimeofday, 2)
+#define __NR_adjtimex                          194
+__SYSCALL(194, sys_adjtimex, 1)
+#define __NR_nanosleep                         195
+__SYSCALL(195, sys_nanosleep, 2)
+#define __NR_getgroups                                 196
+__SYSCALL(196, sys_getgroups, 2)
+#define __NR_setgroups                                 197
+__SYSCALL(197, sys_setgroups, 2)
+#define __NR_sethostname                       198
+__SYSCALL(198, sys_sethostname, 2)
+#define __NR_setdomainname                     199
+__SYSCALL(199, sys_setdomainname, 2)
+#define __NR_syslog                            200
+__SYSCALL(200, sys_syslog, 3)
+#define __NR_vhangup                           201
+__SYSCALL(201, sys_vhangup, 0)
+#define __NR_uselib                            202
+__SYSCALL(202, sys_uselib, 1)
+#define __NR_reboot                            203
+__SYSCALL(203, sys_reboot, 3)
+#define __NR_quotactl                          204
+__SYSCALL(204, sys_quotactl, 4)
+#define __NR_nfsservctl                        205
+__SYSCALL(205, sys_nfsservctl, 3)
+#define __NR__sysctl                           206
+__SYSCALL(206, sys_sysctl, 1)
+#define __NR_bdflush                           207
+__SYSCALL(207, sys_bdflush, 2)
+#define __NR_uname                             208
+__SYSCALL(208, sys_newuname, 1)
+#define __NR_sysinfo                           209
+__SYSCALL(209, sys_sysinfo, 1)
+#define __NR_init_module                       210
+__SYSCALL(210, sys_init_module, 2)
+#define __NR_delete_module                     211
+__SYSCALL(211, sys_delete_module, 1)
+
+#define __NR_sched_setparam                    212
+__SYSCALL(212, sys_sched_setparam, 2)
+#define __NR_sched_getparam                    213
+__SYSCALL(213, sys_sched_getparam, 2)
+#define __NR_sched_setscheduler                214
+__SYSCALL(214, sys_sched_setscheduler, 3)
+#define __NR_sched_getscheduler                215
+__SYSCALL(215, sys_sched_getscheduler, 1)
+#define __NR_sched_get_priority_max            216
+__SYSCALL(216, sys_sched_get_priority_max, 1)
+#define __NR_sched_get_priority_min            217
+__SYSCALL(217, sys_sched_get_priority_min, 1)
+#define __NR_sched_rr_get_interval             218
+__SYSCALL(218, sys_sched_rr_get_interval, 2)
+#define __NR_sched_yield                       219
+__SYSCALL(219, sys_sched_yield, 0)
+#define __NR_sigreturn                         222
+__SYSCALL(222, xtensa_sigreturn, 0)
+
+/* Signal Handling */
+
+#define __NR_restart_syscall                   223
+__SYSCALL(223, sys_restart_syscall, 0)
+#define __NR_sigaltstack                       224
+__SYSCALL(224, xtensa_sigaltstack, 2)
+#define __NR_rt_sigreturn                      225
+__SYSCALL(225, xtensa_rt_sigreturn, 1)
+#define __NR_rt_sigaction                      226
+__SYSCALL(226, sys_rt_sigaction, 4)
+#define __NR_rt_sigprocmask                    227
+__SYSCALL(227, sys_rt_sigprocmask, 4)
+#define __NR_rt_sigpending                     228
+__SYSCALL(228, sys_rt_sigpending, 2)
+#define __NR_rt_sigtimedwait                   229
+__SYSCALL(229, sys_rt_sigtimedwait, 4)
+#define __NR_rt_sigqueueinfo                   230
+__SYSCALL(230, sys_rt_sigqueueinfo, 3)
+#define __NR_rt_sigsuspend                     231
+__SYSCALL(231, xtensa_rt_sigsuspend, 2)
+
+/* Message */
+
+#define __NR_mq_open                           232
+__SYSCALL(232, sys_mq_open, 4)
+#define __NR_mq_unlink                                 233
+__SYSCALL(233, sys_mq_unlink, 1)
+#define __NR_mq_timedsend                      234
+__SYSCALL(234, sys_mq_timedsend, 5)
+#define __NR_mq_timedreceive                   235
+__SYSCALL(235, sys_mq_timedreceive, 5)
+#define __NR_mq_notify                                 236
+__SYSCALL(236, sys_mq_notify, 2)
+#define __NR_mq_getsetattr                     237
+__SYSCALL(237, sys_mq_getsetattr, 3)
+#define __NR_available238                      238
+__SYSCALL(238, sys_ni_syscall, 0)
+
+/* IO */
+
+#define __NR_io_setup                          239
+__SYSCALL(239, sys_io_setup, 2)
+#define __NR_io_destroy                        240
+__SYSCALL(240, sys_io_destroy, 1)
+#define __NR_io_submit                                 241
+__SYSCALL(241, sys_io_submit, 3)
+#define __NR_io_getevents                      242
+__SYSCALL(242, sys_io_getevents, 5)
+#define __NR_io_cancel                                 243
+__SYSCALL(243, sys_io_cancel, 3)
+#define __NR_clock_settime                     244
+__SYSCALL(244, sys_clock_settime, 2)
+#define __NR_clock_gettime                     245
+__SYSCALL(245, sys_clock_gettime, 2)
+#define __NR_clock_getres                      246
+__SYSCALL(246, sys_clock_getres, 2)
+#define __NR_clock_nanosleep                   247
+__SYSCALL(247, sys_clock_nanosleep, 4)
+
+/* Timer */
+
+#define __NR_timer_create                      248
+__SYSCALL(248, sys_timer_create, 3)
+#define __NR_timer_delete                      249
+__SYSCALL(249, sys_timer_delete, 1)
+#define __NR_timer_settime                     250
+__SYSCALL(250, sys_timer_settime, 4)
+#define __NR_timer_gettime                     251
+__SYSCALL(251, sys_timer_gettime, 2)
+#define __NR_timer_getoverrun                  252
+__SYSCALL(252, sys_timer_getoverrun, 1)
+
+/* System */
+
+#define __NR_reserved244                       253
+__SYSCALL(253, sys_ni_syscall, 0)
+#define __NR_lookup_dcookie                    254
+__SYSCALL(254, sys_lookup_dcookie, 4)
+#define __NR_available255                      255
+__SYSCALL(255, sys_ni_syscall, 0)
+#define __NR_add_key                           256
+__SYSCALL(256, sys_add_key, 5)
+#define __NR_request_key                       257
+__SYSCALL(257, sys_request_key, 5)
+#define __NR_keyctl                            258
+__SYSCALL(258, sys_keyctl, 5)
+#define __NR_available259                      259
+__SYSCALL(259, sys_ni_syscall, 0)
+
+#define __NR_syscall_count                     261
+
+/*
+ * sysxtensa syscall handler
+ *
+ * int sysxtensa (SYS_XTENSA_ATOMIC_SET,     ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_ADD,     ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val,    unused);
+ * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ *        a2            a6                   a3    a4      a5
+ */
+
+#define SYS_XTENSA_RESERVED               0     /* don't use this */
+#define SYS_XTENSA_ATOMIC_SET             1     /* set variable */
+#define SYS_XTENSA_ATOMIC_EXG_ADD         2     /* exchange memory and add */
+#define SYS_XTENSA_ATOMIC_ADD             3     /* add to memory */
+#define SYS_XTENSA_ATOMIC_CMP_SWP         4     /* compare and swap */
+
+#define SYS_XTENSA_COUNT                  5     /* count */
+
+#ifdef __KERNEL__
 
 /*
  * "Conditional" syscalls
 #define __ARCH_WANT_SYS_UTIME
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_RT_SIGACTION
-#endif /* __KERNEL__ */
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+
+#endif /* __KERNEL__ */
 
 #endif /* _XTENSA_UNISTD_H */
+
diff --git a/include/asm-xtensa/variant-fsf/core.h b/include/asm-xtensa/variant-fsf/core.h
new file mode 100644 (file)
index 0000000..2f33760
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Xtensa processor core configuration information.
+ *
+ * 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.
+ *
+ * Copyright (C) 1999-2006 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CORE_H
+#define _XTENSA_CORE_H
+
+
+/****************************************************************************
+           Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ *  configured, and a value of 0 otherwise.  These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+                               ISA
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE                  1       /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED            1       /* windowed registers option */
+#define XCHAL_NUM_AREGS                        64      /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2           6       /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE     3       /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG               1       /* debug option */
+#define XCHAL_HAVE_DENSITY             1       /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS               1       /* zero-overhead loops */
+#define XCHAL_HAVE_NSA                 1       /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX              0       /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT                        0       /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS              0       /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16               0       /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32               0       /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH          0       /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_L32R                        1       /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS   1       /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16             0       /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX                        1       /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES       0       /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES  0       /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12          1       /* (obsolete option) */
+#define XCHAL_HAVE_ABS                 1       /* ABS instruction */
+/*#define XCHAL_HAVE_POPC              0*/     /* POPC instruction */
+/*#define XCHAL_HAVE_CRC               0*/     /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC                0       /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I              0       /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION         0       /* speculation */
+#define XCHAL_HAVE_FULL_RESET          1       /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS             1       /* */
+#define XCHAL_NUM_MISC_REGS            2       /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER          0       /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID                        1       /* processor ID register */
+#define XCHAL_HAVE_THREADPTR           1       /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS            0       /* boolean registers */
+#define XCHAL_HAVE_CP                  0       /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG                        0       /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16               0       /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005       0       /* vector floating-point pkg */
+#define XCHAL_HAVE_FP                  0       /* floating point pkg */
+#define XCHAL_HAVE_VECTRA1             0       /* Vectra I  pkg */
+#define XCHAL_HAVE_VECTRALX            0       /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFI2               0       /* HiFi2 Audio Engine pkg */
+
+
+/*----------------------------------------------------------------------
+                               MISC
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES  4       /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH         4       /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH               4       /* data width in bytes */
+/*  In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1       /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION        1       /* unaligned stores cause exc.*/
+
+#define XCHAL_CORE_ID                  "fsf"   /* alphanum core name
+                                                  (CoreID) set in the Xtensa
+                                                  Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID          0x00006700      /* 22-bit sw build ID */
+
+/*
+ *  These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0             0xC103C3FF      /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1             0x0C006700      /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME          "LX2.0.0"       /* full version name */
+#define XCHAL_HW_VERSION_MAJOR         2200    /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR         0       /* minor ver# of targeted hw */
+#define XTHAL_HW_REL_LX2               1
+#define XTHAL_HW_REL_LX2_0             1
+#define XTHAL_HW_REL_LX2_0_0           1
+#define XCHAL_HW_CONFIGID_RELIABLE     1
+/*  If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR     2200    /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR     0       /* minor v of earliest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR     2200    /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR     0       /* minor v of latest tgt hw */
+
+
+/*----------------------------------------------------------------------
+                               CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE          16      /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE          16      /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH         4       /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH         4       /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE              8192    /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE              8192    /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK      0       /* writeback feature */
+
+
+
+
+/****************************************************************************
+    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+                               CACHE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF                 1       /* any outbound PIF present */
+
+/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */
+
+/*  Number of cache sets in log2(lines per way):  */
+#define XCHAL_ICACHE_SETWIDTH          8
+#define XCHAL_DCACHE_SETWIDTH          8
+
+/*  Cache set associativity (number of ways):  */
+#define XCHAL_ICACHE_WAYS              2
+#define XCHAL_DCACHE_WAYS              2
+
+/*  Cache features:  */
+#define XCHAL_ICACHE_LINE_LOCKABLE     0
+#define XCHAL_DCACHE_LINE_LOCKABLE     0
+#define XCHAL_ICACHE_ECC_PARITY                0
+#define XCHAL_DCACHE_ECC_PARITY                0
+
+/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */
+#define XCHAL_CA_BITS                  4
+
+
+/*----------------------------------------------------------------------
+                       INTERNAL I/D RAM/ROMs and XLMI
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM              0       /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM              0       /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM              0       /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM              0       /* number of core data RAMs */
+#define XCHAL_NUM_URAM                 0       /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI                 0       /* number of core XLMI ports */
+
+
+/*----------------------------------------------------------------------
+                       INTERRUPTS and TIMERS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS          1       /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS  1       /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI                 0       /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT              1       /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS               3       /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS           17      /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2      5       /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS                10      /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS            4       /* number of interrupt levels
+                                                  (not including level zero) */
+#define XCHAL_EXCM_LEVEL               1       /* level masked by PS.EXCM */
+       /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/*  Masks of interrupts at each interrupt level:  */
+#define XCHAL_INTLEVEL1_MASK           0x000064F9
+#define XCHAL_INTLEVEL2_MASK           0x00008902
+#define XCHAL_INTLEVEL3_MASK           0x00011204
+#define XCHAL_INTLEVEL4_MASK           0x00000000
+#define XCHAL_INTLEVEL5_MASK           0x00000000
+#define XCHAL_INTLEVEL6_MASK           0x00000000
+#define XCHAL_INTLEVEL7_MASK           0x00000000
+
+/*  Masks of interrupts at each range 1..n of interrupt levels:  */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK  0x000064F9
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK  0x0000EDFB
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK  0x0001FFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK  0x0001FFFF
+
+/*  Level of each interrupt:  */
+#define XCHAL_INT0_LEVEL               1
+#define XCHAL_INT1_LEVEL               2
+#define XCHAL_INT2_LEVEL               3
+#define XCHAL_INT3_LEVEL               1
+#define XCHAL_INT4_LEVEL               1
+#define XCHAL_INT5_LEVEL               1
+#define XCHAL_INT6_LEVEL               1
+#define XCHAL_INT7_LEVEL               1
+#define XCHAL_INT8_LEVEL               2
+#define XCHAL_INT9_LEVEL               3
+#define XCHAL_INT10_LEVEL              1
+#define XCHAL_INT11_LEVEL              2
+#define XCHAL_INT12_LEVEL              3
+#define XCHAL_INT13_LEVEL              1
+#define XCHAL_INT14_LEVEL              1
+#define XCHAL_INT15_LEVEL              2
+#define XCHAL_INT16_LEVEL              3
+#define XCHAL_DEBUGLEVEL               4       /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT    0       /* OCD external db interrupt */
+
+/*  Type of each interrupt:  */
+#define XCHAL_INT0_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT8_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT9_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT10_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT12_TYPE       XTHAL_INTTYPE_TIMER
+#define XCHAL_INT13_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT14_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT15_TYPE       XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT16_TYPE       XTHAL_INTTYPE_SOFTWARE
+
+/*  Masks of interrupts for each type of interrupt:  */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED        0xFFFE0000
+#define XCHAL_INTTYPE_MASK_SOFTWARE    0x0001E000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL        0x0000007F
+#define XCHAL_INTTYPE_MASK_TIMER       0x00001C00
+#define XCHAL_INTTYPE_MASK_NMI         0x00000000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
+
+/*  Interrupt numbers assigned to specific interrupt sources:  */
+#define XCHAL_TIMER0_INTERRUPT         10      /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT         11      /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT         12      /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT         XTHAL_TIMER_UNCONFIGURED
+
+/*  Interrupt numbers for levels at which only one interrupt is configured:  */
+/*  (There are many interrupts each at level(s) 1, 2, 3.)  */
+
+
+/*
+ *  External interrupt vectors/levels.
+ *  These macros describe how Xtensa processor interrupt numbers
+ *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ *  map to external BInterrupt<n> pins, for those interrupts
+ *  configured as external (level-triggered, edge-triggered, or NMI).
+ *  See the Xtensa processor databook for more details.
+ */
+
+/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
+#define XCHAL_EXTINT0_NUM              0       /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM              1       /* (intlevel 2) */
+#define XCHAL_EXTINT2_NUM              2       /* (intlevel 3) */
+#define XCHAL_EXTINT3_NUM              3       /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM              4       /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM              5       /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM              6       /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM              7       /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM              8       /* (intlevel 2) */
+#define XCHAL_EXTINT9_NUM              9       /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+                       EXCEPTIONS and VECTORS
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION              2       /* Xtensa Exception Architecture
+                                                  number: 1 == XEA1 (old)
+                                                          2 == XEA2 (new)
+                                                          0 == XEAX (extern) */
+#define XCHAL_HAVE_XEA1                        0       /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2                        1       /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX                        0       /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS          1       /* exception option */
+#define XCHAL_HAVE_MEM_ECC_PARITY      0       /* local memory ECC/parity */
+
+#define XCHAL_RESET_VECTOR_VADDR       0xFE000020
+#define XCHAL_RESET_VECTOR_PADDR       0xFE000020
+#define XCHAL_USER_VECTOR_VADDR                0xD0000220
+#define XCHAL_USER_VECTOR_PADDR                0x00000220
+#define XCHAL_KERNEL_VECTOR_VADDR      0xD0000200
+#define XCHAL_KERNEL_VECTOR_PADDR      0x00000200
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR   0xD0000290
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR   0x00000290
+#define XCHAL_WINDOW_VECTORS_VADDR     0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR     0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR   0xD0000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR   0x00000240
+#define XCHAL_INTLEVEL3_VECTOR_VADDR   0xD0000250
+#define XCHAL_INTLEVEL3_VECTOR_PADDR   0x00000250
+#define XCHAL_INTLEVEL4_VECTOR_VADDR   0xFE000520
+#define XCHAL_INTLEVEL4_VECTOR_PADDR   0xFE000520
+#define XCHAL_DEBUG_VECTOR_VADDR       XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR       XCHAL_INTLEVEL4_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+                               DEBUG
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD                 1       /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK               2       /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK               2       /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY       1       /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+                               MMU
+  ----------------------------------------------------------------------*/
+
+/*  See <xtensa/config/core-matmap.h> header file for more details.  */
+
+#define XCHAL_HAVE_TLBS                        1       /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY                0       /* one way maps I+D 4GB vaddr */
+#define XCHAL_HAVE_IDENTITY_MAP                0       /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR           0       /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR     0       /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR       0       /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU             1       /* full MMU (with page table
+                                                  [autorefill] and protection)
+                                                  usable for an MMU-based OS */
+/*  If none of the above last 4 are set, it's a custom TLB configuration.  */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2    2       /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2    2       /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS            8       /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS                        4       /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS            2       /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
+
diff --git a/include/asm-xtensa/variant-fsf/tie.h b/include/asm-xtensa/variant-fsf/tie.h
new file mode 100644 (file)
index 0000000..a73c716
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Xtensa processor core configuration information.
+ *
+ * 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.
+ *
+ * Copyright (C) 1999-2006 Tensilica Inc.
+ */
+
+#ifndef XTENSA_TIE_H
+#define XTENSA_TIE_H
+
+/*----------------------------------------------------------------------
+                       COPROCESSORS and EXTRA STATE
+  ----------------------------------------------------------------------*/
+
+#define XCHAL_CP_NUM                   0       /* number of coprocessors */
+#define XCHAL_CP_MASK                  0x00
+
+#endif /*XTENSA_CONFIG_TIE_H*/
+
diff --git a/include/asm-xtensa/xtensa/cacheasm.h b/include/asm-xtensa/xtensa/cacheasm.h
deleted file mode 100644 (file)
index 0cdbb0b..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-#ifndef XTENSA_CACHEASM_H
-#define XTENSA_CACHEASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/cacheasm.h -- assembler-specific cache
- * related definitions that depend on CORE configuration.
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/coreasm.h>
-
-
-/*
- *  This header file defines assembler macros of the form:
- *     <x>cache_<func>
- *  where <x> is 'i' or 'd' for instruction and data caches,
- *  and <func> indicates the function of the macro.
- *
- *  The following functions <func> are defined,
- *  and apply only to the specified cache (I or D):
- *
- *  reset
- *     Resets the cache.
- *
- *  sync
- *     Makes sure any previous cache instructions have been completed;
- *     ie. makes sure any previous cache control operations
- *     have had full effect and been synchronized to memory.
- *     Eg. any invalidate completed [so as not to generate a hit],
- *     any writebacks or other pipelined writes written to memory, etc.
- *
- *  invalidate_line            (single cache line)
- *  invalidate_region          (specified memory range)
- *  invalidate_all             (entire cache)
- *     Invalidates all cache entries that cache
- *     data from the specified memory range.
- *     NOTE: locked entries are not invalidated.
- *
- *  writeback_line             (single cache line)
- *  writeback_region           (specified memory range)
- *  writeback_all              (entire cache)
- *     Writes back to memory all dirty cache entries
- *     that cache data from the specified memory range,
- *     and marks these entries as clean.
- *     NOTE: on some future implementations, this might
- *             also invalidate.
- *     NOTE: locked entries are written back, but never invalidated.
- *     NOTE: instruction caches never implement writeback.
- *
- *  writeback_inv_line         (single cache line)
- *  writeback_inv_region       (specified memory range)
- *  writeback_inv_all          (entire cache)
- *     Writes back to memory all dirty cache entries
- *     that cache data from the specified memory range,
- *     and invalidates these entries (including all clean
- *     cache entries that cache data from that range).
- *     NOTE: locked entries are written back but not invalidated.
- *     NOTE: instruction caches never implement writeback.
- *
- *  lock_line                  (single cache line)
- *  lock_region                        (specified memory range)
- *     Prefetch and lock the specified memory range into cache.
- *     NOTE:  if any part of the specified memory range cannot
- *     be locked, a ??? exception occurs.  These macros don't
- *     do anything special (yet anyway) to handle this situation.
- *
- *  unlock_line                        (single cache line)
- *  unlock_region              (specified memory range)
- *  unlock_all                 (entire cache)
- *     Unlock cache entries that cache the specified memory range.
- *     Entries not already locked are unaffected.
- */
-
-
-
-/***************************   GENERIC -- ALL CACHES   ***************************/
-
-
-/*
- *  The following macros assume the following cache size/parameter limits
- *  in the current Xtensa core implementation:
- *     cache size:     1024 bytes minimum
- *     line size:      16 - 64 bytes
- *     way count:      1 - 4
- *
- *  Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4
- *  Hence the assumption that each loop can execute four cache instructions.
- *
- *  Correspondingly, the offset range of instructions is assumed able to cover
- *  four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for
- *  both hit and indexed cache instructions.  Ie. these offsets are all
- *  valid:  0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64).
- *  This is true of all original cache instructions
- *  (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets
- *  of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2).
- *  This is also true of subsequent cache instructions
- *  (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets
- *  of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4).
- *
- *  (Maximum cache size, currently 32k, doesn't affect the following macros.
- *  Cache ways > MMU min page size cause aliasing but that's another matter.)
- */
-
-
-
-/*
- *  Macro to apply an 'indexed' cache instruction to the entire cache.
- *
- *  Parameters:
- *     cainst          instruction/ that takes an address register parameter
- *                     and an offset parameter (in range 0 .. 3*linesize).
- *     size            size of cache in bytes
- *     linesize        size of cache line in bytes
- *     assoc_or1       number of associativities (ways/sets) in cache
- *                     if all sets affected by cainst,
- *                     or 1 if only one set (or not all sets) of the cache
- *                     is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]).
- *     aa, ab          unique address registers (temporaries)
- */
-
-       .macro  cache_index_all         cainst, size, linesize, assoc_or1, aa, ab
-
-       //  Sanity-check on cache parameters:
-       .ifne   (\size % (\linesize * \assoc_or1 * 4))
-       .err    //  cache configuration outside expected/supported range!
-       .endif
-
-       //  \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst.
-       movi    \aa, (\size / (\linesize * \assoc_or1 * 4))
-       // Possible improvement: need only loop if \aa > 1 ;
-       // however that particular condition is highly unlikely.
-       movi    \ab, 0          // to iterate over cache
-       floop           \aa, cachex\@
-       \cainst         \ab, 0*\linesize
-       \cainst         \ab, 1*\linesize
-       \cainst         \ab, 2*\linesize
-       \cainst         \ab, 3*\linesize
-       addi            \ab, \ab, 4*\linesize   // move to next line
-       floopend        \aa, cachex\@
-
-       .endm
-
-
-/*
- *  Macro to apply a 'hit' cache instruction to a memory region,
- *  ie. to any cache entries that cache a specified portion (region) of memory.
- *  Takes care of the unaligned cases, ie. may apply to one
- *  more cache line than $asize / lineSize if $aaddr is not aligned.
- *
- *
- *  Parameters are:
- *     cainst  instruction/macro that takes an address register parameter
- *             and an offset parameter (currently always zero)
- *             and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.)
- *     linesize_log2   log2(size of cache line in bytes)
- *     addr    register containing start address of region (clobbered)
- *     asize   register containing size of the region in bytes (clobbered)
- *     askew   unique register used as temporary
- *
- * !?!?! 2DO: optimization: iterate max(cache_size and \asize) / linesize
- */
-
-       .macro  cache_hit_region        cainst, linesize_log2, addr, asize, askew
-
-       //  Make \asize the number of iterations:
-       extui   \askew, \addr, 0, \linesize_log2        // get unalignment amount of \addr
-       add     \asize, \asize, \askew                  // ... and add it to \asize
-       addi    \asize, \asize, (1 << \linesize_log2) - 1       // round up!
-       srli    \asize, \asize, \linesize_log2
-
-       //  Iterate over region:
-       floopnez        \asize, cacheh\@
-       \cainst         \addr, 0
-       addi            \addr, \addr, (1 << \linesize_log2)     // move to next line
-       floopend        \asize, cacheh\@
-
-       .endm
-
-
-
-
-
-/***************************   INSTRUCTION CACHE   ***************************/
-
-
-/*
- *  Reset/initialize the instruction cache by simply invalidating it:
- *  (need to unlock first also, if cache locking implemented):
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  icache_reset    aa, ab
-       icache_unlock_all       \aa, \ab
-       icache_invalidate_all   \aa, \ab
-       .endm
-
-
-/*
- * Synchronize after an instruction cache operation,
- * to be sure everything is in sync with memory as to be
- * expected following any previous instruction cache control operations.
- *
- * Parameters are:
- *     ar      an address register (temporary) (currently unused, but may be used in future)
- */
-       .macro  icache_sync     ar
-#if XCHAL_ICACHE_SIZE > 0
-       isync
-#endif
-       .endm
-
-
-
-/*
- *  Invalidate a single line of the instruction cache.
- *  Parameters are:
- *     ar      address register that contains (virtual) address to invalidate
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  (optional) offset to add to \ar to compute effective address to invalidate
- *             (note: some number of lsbits are ignored)
- */
-       .macro  icache_invalidate_line  ar, offset
-#if XCHAL_ICACHE_SIZE > 0
-       ihi     \ar, \offset            // invalidate icache line
-       /*
-        *  NOTE:  in some version of the silicon [!!!SHOULD HAVE BEEN DOCUMENTED!!!]
-        *  'ihi' doesn't work, so it had been replaced with 'iii'
-        *  (which would just invalidate more than it should,
-        *  which should be okay other than the performance hit
-        *  because cache locking did not exist in that version,
-        *  unless user somehow relies on something being cached).
-        *  [WHAT VERSION IS IT!!?!?
-        *  IS THERE ANY WAY TO TEST FOR THAT HERE, TO OUTPUT 'III' ONLY IF NEEDED!?!?].
-        *
-        *      iii     \ar, \offset
-        */
-       icache_sync     \ar
-#endif
-       .endm
-
-
-
-
-/*
- *  Invalidate instruction  cache entries that cache a specified portion of memory.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  icache_invalidate_region        astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0
-       //  Instruction cache region invalidation:
-       cache_hit_region        ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
-       icache_sync     \ac
-       //  End of instruction cache region invalidation
-#endif
-       .endm
-
-
-
-/*
- *  Invalidate entire instruction cache.
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  icache_invalidate_all   aa, ab
-#if XCHAL_ICACHE_SIZE > 0
-       //  Instruction cache invalidation:
-       cache_index_all         iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab
-       icache_sync     \aa
-       //  End of instruction cache invalidation
-#endif
-       .endm
-
-
-
-/*
- *  Lock (prefetch & lock) a single line of the instruction cache.
- *
- *  Parameters are:
- *     ar      address register that contains (virtual) address to lock
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to lock
- *             (note: some number of lsbits are ignored)
- */
-       .macro  icache_lock_line        ar, offset
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
-       ipfl    \ar, \offset    /* prefetch and lock icache line */
-       icache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Lock (prefetch & lock) a specified portion of memory into the instruction cache.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  icache_lock_region      astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
-       //  Instruction cache region lock:
-       cache_hit_region        ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
-       icache_sync     \ac
-       //  End of instruction cache region lock
-#endif
-       .endm
-
-
-
-/*
- *  Unlock a single line of the instruction cache.
- *
- *  Parameters are:
- *     ar      address register that contains (virtual) address to unlock
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to unlock
- *             (note: some number of lsbits are ignored)
- */
-       .macro  icache_unlock_line      ar, offset
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
-       ihu     \ar, \offset    /* unlock icache line */
-       icache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Unlock a specified portion of memory from the instruction cache.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  icache_unlock_region    astart, asize, ac
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
-       //  Instruction cache region unlock:
-       cache_hit_region        ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
-       icache_sync     \ac
-       //  End of instruction cache region unlock
-#endif
-       .endm
-
-
-
-/*
- *  Unlock entire instruction cache.
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  icache_unlock_all       aa, ab
-#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
-       //  Instruction cache unlock:
-       cache_index_all         iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab
-       icache_sync     \aa
-       //  End of instruction cache unlock
-#endif
-       .endm
-
-
-
-
-
-/***************************   DATA CACHE   ***************************/
-
-
-
-/*
- *  Reset/initialize the data cache by simply invalidating it
- *  (need to unlock first also, if cache locking implemented):
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  dcache_reset    aa, ab
-       dcache_unlock_all       \aa, \ab
-       dcache_invalidate_all   \aa, \ab
-       .endm
-
-
-
-
-/*
- * Synchronize after a data cache operation,
- * to be sure everything is in sync with memory as to be
- * expected following any previous data cache control operations.
- *
- * Parameters are:
- *     ar      an address register (temporary) (currently unused, but may be used in future)
- */
-       .macro  dcache_sync     ar
-#if XCHAL_DCACHE_SIZE > 0
-       //  This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient:
-       //memw          // synchronize data cache changes relative to subsequent memory accesses
-       //isync         // be conservative and ISYNC as well (just to be sure)
-
-       dsync
-#endif
-       .endm
-
-
-
-/*
- * Synchronize after a data store operation,
- * to be sure the stored data is completely off the processor
- * (and assuming there is no buffering outside the processor,
- *  that the data is in memory).  This may be required to
- * ensure that the processor's write buffers are emptied.
- * A MEMW followed by a read guarantees this, by definition.
- * We also try to make sure the read itself completes.
- *
- * Parameters are:
- *     ar      an address register (temporary)
- */
-       .macro  write_sync      ar
-       memw                    // ensure previous memory accesses are complete prior to subsequent memory accesses
-       l32i    \ar, sp, 0      // completing this read ensures any previous write has completed, because of MEMW
-       //slot
-       add     \ar, \ar, \ar   // use the result of the read to help ensure the read completes (in future architectures)
-       .endm
-
-
-/*
- *  Invalidate a single line of the data cache.
- *  Parameters are:
- *     ar      address register that contains (virtual) address to invalidate
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  (optional) offset to add to \ar to compute effective address to invalidate
- *             (note: some number of lsbits are ignored)
- */
-       .macro  dcache_invalidate_line  ar, offset
-#if XCHAL_DCACHE_SIZE > 0
-       dhi     \ar, \offset
-       dcache_sync     \ar
-#endif
-       .endm
-
-
-
-
-
-/*
- *  Invalidate data cache entries that cache a specified portion of memory.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  dcache_invalidate_region        astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0
-       //  Data cache region invalidation:
-       cache_hit_region        dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
-       dcache_sync     \ac
-       //  End of data cache region invalidation
-#endif
-       .endm
-
-
-
-#if 0
-/*
- *  This is a work-around for a bug in SiChip1 (???).
- *  There should be a proper mechanism for not outputting
- *  these instructions when not needed.
- *  To enable work-around, uncomment this and replace 'dii'
- *  with 'dii_s1' everywhere, eg. in dcache_invalidate_all
- *  macro below.
- */
-       .macro  dii_s1  ar, offset
-       dii     \ar, \offset
-       or      \ar, \ar, \ar
-       or      \ar, \ar, \ar
-       or      \ar, \ar, \ar
-       or      \ar, \ar, \ar
-       .endm
-#endif
-
-
-/*
- *  Invalidate entire data cache.
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  dcache_invalidate_all   aa, ab
-#if XCHAL_DCACHE_SIZE > 0
-       //  Data cache invalidation:
-       cache_index_all         dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab
-       dcache_sync     \aa
-       //  End of data cache invalidation
-#endif
-       .endm
-
-
-
-/*
- *  Writeback a single line of the data cache.
- *  Parameters are:
- *     ar      address register that contains (virtual) address to writeback
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to writeback
- *             (note: some number of lsbits are ignored)
- */
-       .macro  dcache_writeback_line   ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
-       dhwb    \ar, \offset
-       dcache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Writeback dirty data cache entries that cache a specified portion of memory.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  dcache_writeback_region         astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
-       //  Data cache region writeback:
-       cache_hit_region        dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
-       dcache_sync     \ac
-       //  End of data cache region writeback
-#endif
-       .endm
-
-
-
-/*
- *  Writeback entire data cache.
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  dcache_writeback_all    aa, ab
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
-       //  Data cache writeback:
-       cache_index_all         diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
-       dcache_sync     \aa
-       //  End of data cache writeback
-#endif
-       .endm
-
-
-
-/*
- *  Writeback and invalidate a single line of the data cache.
- *  Parameters are:
- *     ar      address register that contains (virtual) address to writeback and invalidate
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to writeback and invalidate
- *             (note: some number of lsbits are ignored)
- */
-       .macro  dcache_writeback_inv_line       ar, offset
-#if XCHAL_DCACHE_SIZE > 0
-       dhwbi   \ar, \offset    /* writeback and invalidate dcache line */
-       dcache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Writeback and invalidate data cache entries that cache a specified portion of memory.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  dcache_writeback_inv_region     astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0
-       //  Data cache region writeback and invalidate:
-       cache_hit_region        dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
-       dcache_sync     \ac
-       //  End of data cache region writeback and invalidate
-#endif
-       .endm
-
-
-
-/*
- *  Writeback and invalidate entire data cache.
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  dcache_writeback_inv_all        aa, ab
-#if XCHAL_DCACHE_SIZE > 0
-       //  Data cache writeback and invalidate:
-#if XCHAL_DCACHE_IS_WRITEBACK
-       cache_index_all         diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
-       dcache_sync     \aa
-#else /*writeback*/
-       //  Data cache does not support writeback, so just invalidate: */
-       dcache_invalidate_all   \aa, \ab
-#endif /*writeback*/
-       //  End of data cache writeback and invalidate
-#endif
-       .endm
-
-
-
-
-/*
- *  Lock (prefetch & lock) a single line of the data cache.
- *
- *  Parameters are:
- *     ar      address register that contains (virtual) address to lock
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to lock
- *             (note: some number of lsbits are ignored)
- */
-       .macro  dcache_lock_line        ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
-       dpfl    \ar, \offset    /* prefetch and lock dcache line */
-       dcache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Lock (prefetch & lock) a specified portion of memory into the data cache.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  dcache_lock_region      astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
-       //  Data cache region lock:
-       cache_hit_region        dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
-       dcache_sync     \ac
-       //  End of data cache region lock
-#endif
-       .endm
-
-
-
-/*
- *  Unlock a single line of the data cache.
- *
- *  Parameters are:
- *     ar      address register that contains (virtual) address to unlock
- *             (may get clobbered in a future implementation, but not currently)
- *     offset  offset to add to \ar to compute effective address to unlock
- *             (note: some number of lsbits are ignored)
- */
-       .macro  dcache_unlock_line      ar, offset
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
-       dhu     \ar, \offset    /* unlock dcache line */
-       dcache_sync     \ar
-#endif
-       .endm
-
-
-
-/*
- *  Unlock a specified portion of memory from the data cache.
- *  Parameters are:
- *     astart  start address (register gets clobbered)
- *     asize   size of the region in bytes (register gets clobbered)
- *     ac      unique register used as temporary
- */
-       .macro  dcache_unlock_region    astart, asize, ac
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
-       //  Data cache region unlock:
-       cache_hit_region        dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
-       dcache_sync     \ac
-       //  End of data cache region unlock
-#endif
-       .endm
-
-
-
-/*
- *  Unlock entire data cache.
- *
- *  Parameters:
- *     aa, ab          unique address registers (temporaries)
- */
-       .macro  dcache_unlock_all       aa, ab
-#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
-       //  Data cache unlock:
-       cache_index_all         diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
-       dcache_sync     \aa
-       //  End of data cache unlock
-#endif
-       .endm
-
-
-#endif /*XTENSA_CACHEASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/cacheattrasm.h b/include/asm-xtensa/xtensa/cacheattrasm.h
deleted file mode 100644 (file)
index 1c3e117..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-#ifndef XTENSA_CACHEATTRASM_H
-#define XTENSA_CACHEATTRASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/cacheattrasm.h -- assembler-specific
- * CACHEATTR register related definitions that depend on CORE
- * configuration.
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/coreasm.h>
-
-
-/*
- *  This header file defines assembler macros of the form:
- *     <x>cacheattr_<func>
- *  where:
- *     <x> is 'i', 'd' or absent for instruction, data
- *             or both caches; and
- *     <func> indicates the function of the macro.
- *
- *  The following functions are defined:
- *
- *  icacheattr_get
- *     Reads I-cache CACHEATTR into a2 (clobbers a3-a5).
- *
- *  dcacheattr_get
- *     Reads D-cache CACHEATTR into a2 (clobbers a3-a5).
- *     (Note:  for configs with a real CACHEATTR register, the
- *      above two macros are identical.)
- *
- *  cacheattr_set
- *     Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered).
- *     Works even when changing one's own code's attributes.
- *
- *  icacheattr_is_enabled  label
- *     Branches to \label if I-cache appears to have been enabled
- *     (eg. if CACHEATTR contains a cache-enabled attribute).
- *     (clobbers a2-a5,SAR)
- *
- *  dcacheattr_is_enabled  label
- *     Branches to \label if D-cache appears to have been enabled
- *     (eg. if CACHEATTR contains a cache-enabled attribute).
- *     (clobbers a2-a5,SAR)
- *
- *  cacheattr_is_enabled  label
- *     Branches to \label if either I-cache or D-cache appears to have been enabled
- *     (eg. if CACHEATTR contains a cache-enabled attribute).
- *     (clobbers a2-a5,SAR)
- *
- *  The following macros are only defined under certain conditions:
- *
- *  icacheattr_set     (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
- *     Writes I-cache CACHEATTR from a2 (a3-a8 clobbered).
- *
- *  dcacheattr_set     (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
- *     Writes D-cache CACHEATTR from a2 (a3-a8 clobbered).
- */
-
-
-
-/***************************   GENERIC -- ALL CACHES   ***************************/
-
-/*
- *  _cacheattr_get
- *
- *  (Internal macro.)
- *  Returns value of CACHEATTR register (or closest equivalent) in a2.
- *
- *  Entry:
- *     (none)
- *  Exit:
- *     a2      value read from CACHEATTR
- *     a3-a5   clobbered (temporaries)
- */
-       .macro  _cacheattr_get  tlb
-#if XCHAL_HAVE_CACHEATTR
-       rsr     a2, CACHEATTR
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       //  We have a config that "mimics" CACHEATTR using a simplified
-       //  "MMU" composed of a single statically-mapped way.
-       //  DTLB and ITLB are independent, so there's no single
-       //  cache attribute that can describe both.  So for now
-       //  just return the DTLB state.
-       movi    a5, 0xE0000000
-       movi    a2, 0
-       movi    a3, 0
-1:     add     a3, a3, a5      // next segment
-       r&tlb&1 a4, a3          // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0
-       dsync   // interlock???
-       slli    a2, a2, 4
-       extui   a4, a4, 0, 4    // extract CA
-       or      a2, a2, a4
-       bnez    a3, 1b
-#else
-       //  This macro isn't applicable to arbitrary MMU configurations.
-       //  Just return zero.
-       movi    a2, 0
-#endif
-       .endm
-
-       .macro  icacheattr_get
-       _cacheattr_get  itlb
-       .endm
-
-       .macro  dcacheattr_get
-       _cacheattr_get  dtlb
-       .endm
-
-
-#define XCHAL_CACHEATTR_ALL_BYPASS     0x22222222      /* default (powerup/reset) value of CACHEATTR, all BYPASS
-                                                          mode (ie. disabled/bypassed caches) */
-
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-
-#define XCHAL_FCA_ENAMASK      0x001A  /* bitmap of fetch attributes that require enabled icache */
-#define XCHAL_LCA_ENAMASK      0x0003  /* bitmap of load  attributes that require enabled dcache */
-#define XCHAL_SCA_ENAMASK      0x0003  /* bitmap of store attributes that require enabled dcache */
-#define XCHAL_LSCA_ENAMASK     (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK)   /* l/s attrs requiring enabled dcache */
-#define XCHAL_ALLCA_ENAMASK    (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK)  /* all attrs requiring enabled caches */
-
-/*
- *  _cacheattr_is_enabled
- *
- *  (Internal macro.)
- *  Branches to \label if CACHEATTR in a2 indicates an enabled
- *  cache, using mask in a3.
- *
- *  Parameters:
- *     label   where to branch to if cache is enabled
- *  Entry:
- *     a2      contains CACHEATTR value used to determine whether
- *             caches are enabled
- *     a3      16-bit constant where each bit correspond to
- *             one of the 16 possible CA values (in a CACHEATTR mask);
- *             CA values that indicate the cache is enabled
- *             have their corresponding bit set in this mask
- *             (eg. use XCHAL_xCA_ENAMASK , above)
- *  Exit:
- *     a2,a4,a5        clobbered
- *     SAR             clobbered
- */
-       .macro  _cacheattr_is_enabled   label
-       movi    a4, 8           // loop 8 times
-.Lcaife\@:
-       extui   a5, a2, 0, 4    // get CA nibble
-       ssr     a5              // index into mask according to CA...
-       srl     a5, a3          // ...and get CA's mask bit in a5 bit 0
-       bbsi.l  a5, 0, \label   // if CA indicates cache enabled, jump to label
-       srli    a2, a2, 4       // next nibble
-       addi    a4, a4, -1
-       bnez    a4, .Lcaife\@   // loop for each nibble
-       .endm
-
-#else /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
-       .macro  _cacheattr_is_enabled   label
-       j       \label          // macro not applicable, assume caches always enabled
-       .endm
-#endif /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
-
-
-
-/*
- *  icacheattr_is_enabled
- *
- *  Branches to \label if I-cache is enabled.
- *
- *  Parameters:
- *     label   where to branch to if icache is enabled
- *  Entry:
- *     (none)
- *  Exit:
- *     a2-a5, SAR      clobbered (temporaries)
- */
-       .macro  icacheattr_is_enabled   label
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       icacheattr_get
-       movi    a3, XCHAL_FCA_ENAMASK
-#endif
-       _cacheattr_is_enabled   \label
-       .endm
-
-/*
- *  dcacheattr_is_enabled
- *
- *  Branches to \label if D-cache is enabled.
- *
- *  Parameters:
- *     label   where to branch to if dcache is enabled
- *  Entry:
- *     (none)
- *  Exit:
- *     a2-a5, SAR      clobbered (temporaries)
- */
-       .macro  dcacheattr_is_enabled   label
-#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       dcacheattr_get
-       movi    a3, XCHAL_LSCA_ENAMASK
-#endif
-       _cacheattr_is_enabled   \label
-       .endm
-
-/*
- *  cacheattr_is_enabled
- *
- *  Branches to \label if either I-cache or D-cache is enabled.
- *
- *  Parameters:
- *     label   where to branch to if a cache is enabled
- *  Entry:
- *     (none)
- *  Exit:
- *     a2-a5, SAR      clobbered (temporaries)
- */
-       .macro  cacheattr_is_enabled    label
-#if XCHAL_HAVE_CACHEATTR
-       rsr     a2, CACHEATTR
-       movi    a3, XCHAL_ALLCA_ENAMASK
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       icacheattr_get
-       movi    a3, XCHAL_FCA_ENAMASK
-       _cacheattr_is_enabled   \label
-       dcacheattr_get
-       movi    a3, XCHAL_LSCA_ENAMASK
-#endif
-       _cacheattr_is_enabled   \label
-       .endm
-
-
-
-/*
- *  The ISA does not have a defined way to change the
- *  instruction cache attributes of the running code,
- *  ie. of the memory area that encloses the current PC.
- *  However, each micro-architecture (or class of
- *  configurations within a micro-architecture)
- *  provides a way to deal with this issue.
- *
- *  Here are a few macros used to implement the relevant
- *  approach taken.
- */
-
-#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       //  We have a config that "mimics" CACHEATTR using a simplified
-       //  "MMU" composed of a single statically-mapped way.
-
-/*
- *  icacheattr_set
- *
- *  Entry:
- *     a2              cacheattr value to set
- *  Exit:
- *     a2              unchanged
- *     a3-a8           clobbered (temporaries)
- */
-       .macro  icacheattr_set
-
-       movi    a5, 0xE0000000  // mask of upper 3 bits
-       movi    a6, 3f          // PC where ITLB is set
-       movi    a3, 0           // start at region 0 (0 .. 7)
-       and     a6, a6, a5      // upper 3 bits of local PC area
-       mov     a7, a2          // copy a2 so it doesn't get clobbered
-       j       3f
-
-# if XCHAL_HAVE_XLT_CACHEATTR
-       //  Can do translations, use generic method:
-1:     sub     a6, a3, a5      // address of some other segment
-       ritlb1  a8, a6          // save its PPN+CA
-       dsync   // interlock??
-       witlb   a4, a6          // make it translate to this code area
-       movi    a6, 5f          // where to jump into it
-       isync
-       sub     a6, a6, a5      // adjust jump address within that other segment
-       jx      a6
-
-       //  Note that in the following code snippet, which runs at a different virtual
-       //  address than it is assembled for, we avoid using literals (eg. via movi/l32r)
-       //  just in case literals end up in a different 512 MB segment, and we avoid
-       //  instructions that rely on the current PC being what is expected.
-       //
-       .align  4
-       _j      6f              // this is at label '5' minus 4 bytes
-       .align  4
-5:     witlb   a4, a3          // we're in other segment, now can write previous segment's CA
-       isync
-       add     a6, a6, a5      // back to previous segment
-       addi    a6, a6, -4      // next jump label
-       jx      a6
-
-6:     sub     a6, a3, a5      // address of some other segment
-       witlb   a8, a6          // restore PPN+CA of other segment
-       mov     a6, a3          // restore a6
-       isync
-# else /* XCHAL_HAVE_XLT_CACHEATTR */
-       //  Use micro-architecture specific method.
-       //  The following 4-instruction sequence is aligned such that
-       //  it all fits within a single I-cache line.  Sixteen byte
-       //  alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE
-       //  actually causes problems because that can be greater than
-       //  the alignment of the reset vector, where this macro is often
-       //  invoked, which would cause the linker to align the reset
-       //  vector code away from the reset vector!!).
-       .align  16 /*XCHAL_ICACHE_LINESIZE*/
-1:     _witlb  a4, a3          // write wired PTE (CA, no PPN) of 512MB segment to ITLB
-       _isync
-       nop
-       nop
-# endif /* XCHAL_HAVE_XLT_CACHEATTR */
-       beq     a3, a5, 4f      // done?
-
-       //  Note that in the WITLB loop, we don't do any load/stores
-       //  (may not be an issue here, but it is important in the DTLB case).
-2:     srli    a7, a7, 4       // next CA
-       sub     a3, a3, a5      // next segment (add 0x20000000)
-3:
-# if XCHAL_HAVE_XLT_CACHEATTR  /* if have translation, preserve it */
-       ritlb1  a8, a3          // get current PPN+CA of segment
-       dsync   // interlock???
-       extui   a4, a7, 0, 4    // extract CA to set
-       srli    a8, a8, 4       // clear CA but keep PPN ...
-       slli    a8, a8, 4       // ...
-       add     a4, a4, a8      // combine new CA with PPN to preserve
-# else
-       extui   a4, a7, 0, 4    // extract CA
-# endif
-       beq     a3, a6, 1b      // current PC's region? if so, do it in a safe way
-       witlb   a4, a3          // write wired PTE (CA [+PPN]) of 512MB segment to ITLB
-       bne     a3, a5, 2b
-       isync                   // make sure all ifetch changes take effect
-4:
-       .endm   // icacheattr_set
-
-
-/*
- *  dcacheattr_set
- *
- *  Entry:
- *     a2              cacheattr value to set
- *  Exit:
- *     a2              unchanged
- *     a3-a8           clobbered (temporaries)
- */
-
-       .macro  dcacheattr_set
-
-       movi    a5, 0xE0000000  // mask of upper 3 bits
-       movi    a3, 0           // start at region 0 (0 .. 7)
-       mov     a7, a2          // copy a2 so it doesn't get clobbered
-       j       3f
-       //  Note that in the WDTLB loop, we don't do any load/stores
-       //  (including implicit l32r via movi) because it isn't safe.
-2:     srli    a7, a7, 4       // next CA
-       sub     a3, a3, a5      // next segment (add 0x20000000)
-3:
-# if XCHAL_HAVE_XLT_CACHEATTR  /* if have translation, preserve it */
-       rdtlb1  a8, a3          // get current PPN+CA of segment
-       dsync   // interlock???
-       extui   a4, a7, 0, 4    // extract CA to set
-       srli    a8, a8, 4       // clear CA but keep PPN ...
-       slli    a8, a8, 4       // ...
-       add     a4, a4, a8      // combine new CA with PPN to preserve
-# else
-       extui   a4, a7, 0, 4    // extract CA to set
-# endif
-       wdtlb   a4, a3          // write wired PTE (CA [+PPN]) of 512MB segment to DTLB
-       bne     a3, a5, 2b
-       dsync                   // make sure all data path changes take effect
-       .endm   // dcacheattr_set
-
-#endif /* XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
-
-
-
-/*
- *  cacheattr_set
- *
- *  Macro that sets the current CACHEATTR safely
- *  (both i and d) according to the current contents of a2.
- *  It works even when changing the cache attributes of
- *  the currently running code.
- *
- *  Entry:
- *     a2              cacheattr value to set
- *  Exit:
- *     a2              unchanged
- *     a3-a8           clobbered (temporaries)
- */
-       .macro  cacheattr_set
-
-#if XCHAL_HAVE_CACHEATTR
-# if XCHAL_ICACHE_LINESIZE < 4
-       //  No i-cache, so can always safely write to CACHEATTR:
-       wsr     a2, CACHEATTR
-# else
-       //  The Athens micro-architecture, when using the old
-       //  exception architecture option (ie. with the CACHEATTR register)
-       //  allows changing the cache attributes of the running code
-       //  using the following exact sequence aligned to be within
-       //  an instruction cache line.  (NOTE: using XCHAL_ICACHE_LINESIZE
-       //  alignment actually causes problems because that can be greater
-       //  than the alignment of the reset vector, where this macro is often
-       //  invoked, which would cause the linker to align the reset
-       //  vector code away from the reset vector!!).
-       j       1f
-       .align  16 /*XCHAL_ICACHE_LINESIZE*/    // align to within an I-cache line
-1:     _wsr    a2, CACHEATTR
-       _isync
-       nop
-       nop
-# endif
-#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
-       //  DTLB and ITLB are independent, but to keep semantics
-       //  of this macro we simply write to both.
-       icacheattr_set
-       dcacheattr_set
-#else
-       //  This macro isn't applicable to arbitrary MMU configurations.
-       //  Do nothing in this case.
-#endif
-       .endm
-
-
-#endif /*XTENSA_CACHEATTRASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/core.h b/include/asm-xtensa/xtensa/config-linux_be/core.h
deleted file mode 100644 (file)
index d54fe5e..0000000
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- * xtensa/config/core.h -- HAL definitions that are dependent on CORE configuration
- *
- *  This header file is sometimes referred to as the "compile-time HAL" or CHAL.
- *  It was generated for a specific Xtensa processor configuration.
- *
- *  Source for configuration-independent binaries (which link in a
- *  configuration-specific HAL library) must NEVER include this file.
- *  It is perfectly normal, however, for the HAL source itself to include this file.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2.1 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_CORE_H
-#define XTENSA_CONFIG_CORE_H
-
-#include <xtensa/hal.h>
-
-
-/*----------------------------------------------------------------------
-                               GENERAL
-  ----------------------------------------------------------------------*/
-
-/*
- *  Separators for macros that expand into arrays.
- *  These can be predefined by files that #include this one,
- *  when different separators are required.
- */
-/*  Element separator for macros that expand into 1-dimensional arrays:  */
-#ifndef XCHAL_SEP
-#define XCHAL_SEP                      ,
-#endif
-/*  Array separator for macros that expand into 2-dimensional arrays:  */
-#ifndef XCHAL_SEP2
-#define XCHAL_SEP2                     },{
-#endif
-
-
-/*----------------------------------------------------------------------
-                               ENDIANNESS
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_BE                  1
-#define XCHAL_HAVE_LE                  0
-#define XCHAL_MEMORY_ORDER             XTHAL_BIGENDIAN
-
-
-/*----------------------------------------------------------------------
-                               REGISTER WINDOWS
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_WINDOWED            1       /* 1 if windowed registers option configured, 0 otherwise */
-#define XCHAL_NUM_AREGS                        64      /* number of physical address regs */
-#define XCHAL_NUM_AREGS_LOG2           6       /* log2(XCHAL_NUM_AREGS) */
-
-
-/*----------------------------------------------------------------------
-                               ADDRESS ALIGNMENT
-  ----------------------------------------------------------------------*/
-
-/*  These apply to a selected set of core load and store instructions only (see ISA):  */
-#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1       /* 1 if unaligned loads cause an exception, 0 otherwise */
-#define XCHAL_UNALIGNED_STORE_EXCEPTION        1       /* 1 if unaligned stores cause an exception, 0 otherwise */
-
-
-/*----------------------------------------------------------------------
-                               INTERRUPTS
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_INTERRUPTS          1       /* 1 if interrupt option configured, 0 otherwise */
-#define XCHAL_HAVE_HIGHPRI_INTERRUPTS  1       /* 1 if high-priority interrupt option configured, 0 otherwise */
-#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS        XCHAL_HAVE_HIGHPRI_INTERRUPTS
-#define XCHAL_HAVE_NMI                 0       /* 1 if NMI option configured, 0 otherwise */
-#define XCHAL_NUM_INTERRUPTS           17      /* number of interrupts */
-#define XCHAL_NUM_INTERRUPTS_LOG2      5       /* number of bits to hold an interrupt number: roundup(log2(number of interrupts)) */
-#define XCHAL_NUM_EXTINTERRUPTS                10      /* number of external interrupts */
-#define XCHAL_NUM_INTLEVELS            4       /* number of interrupt levels (not including level zero!) */
-#define XCHAL_NUM_LOWPRI_LEVELS                1                       /* number of low-priority interrupt levels (always 1) */
-#define XCHAL_FIRST_HIGHPRI_LEVEL      (XCHAL_NUM_LOWPRI_LEVELS+1)     /* level of first high-priority interrupt (always 2) */
-#define XCHAL_EXCM_LEVEL               1                       /* level of interrupts masked by PS.EXCM (XEA2 only; always 1 in T10xx);
-                                                                  for XEA1, where there is no PS.EXCM, this is always 1;
-                                                                  interrupts at levels FIRST_HIGHPRI <= n <= EXCM_LEVEL, if any,
-                                                                  are termed "medium priority" interrupts (post T10xx only) */
-/*  Note:  1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15  */
-
-/*  Masks of interrupts at each interrupt level:  */
-#define XCHAL_INTLEVEL0_MASK           0x00000000
-#define XCHAL_INTLEVEL1_MASK           0x000064F9
-#define XCHAL_INTLEVEL2_MASK           0x00008902
-#define XCHAL_INTLEVEL3_MASK           0x00011204
-#define XCHAL_INTLEVEL4_MASK           0x00000000
-#define XCHAL_INTLEVEL5_MASK           0x00000000
-#define XCHAL_INTLEVEL6_MASK           0x00000000
-#define XCHAL_INTLEVEL7_MASK           0x00000000
-#define XCHAL_INTLEVEL8_MASK           0x00000000
-#define XCHAL_INTLEVEL9_MASK           0x00000000
-#define XCHAL_INTLEVEL10_MASK          0x00000000
-#define XCHAL_INTLEVEL11_MASK          0x00000000
-#define XCHAL_INTLEVEL12_MASK          0x00000000
-#define XCHAL_INTLEVEL13_MASK          0x00000000
-#define XCHAL_INTLEVEL14_MASK          0x00000000
-#define XCHAL_INTLEVEL15_MASK          0x00000000
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_INTLEVEL_MASKS           0x00000000      XCHAL_SEP \
-                                       0x000064F9      XCHAL_SEP \
-                                       0x00008902      XCHAL_SEP \
-                                       0x00011204      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000      XCHAL_SEP \
-                                       0x00000000
-
-/*  Masks of interrupts at each range 1..n of interrupt levels:  */
-#define XCHAL_INTLEVEL0_ANDBELOW_MASK  0x00000000
-#define XCHAL_INTLEVEL1_ANDBELOW_MASK  0x000064F9
-#define XCHAL_INTLEVEL2_ANDBELOW_MASK  0x0000EDFB
-#define XCHAL_INTLEVEL3_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL4_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL5_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL6_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL7_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL8_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL9_ANDBELOW_MASK  0x0001FFFF
-#define XCHAL_INTLEVEL10_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL11_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL12_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL13_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL14_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_INTLEVEL15_ANDBELOW_MASK 0x0001FFFF
-#define XCHAL_LOWPRI_MASK              XCHAL_INTLEVEL1_ANDBELOW_MASK   /* mask of all low-priority interrupts */
-#define XCHAL_EXCM_MASK                        XCHAL_INTLEVEL1_ANDBELOW_MASK   /* mask of all interrupts masked by PS.EXCM (or CEXCM) */
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_INTLEVEL_ANDBELOW_MASKS  0x00000000      XCHAL_SEP \
-                                       0x000064F9      XCHAL_SEP \
-                                       0x0000EDFB      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF      XCHAL_SEP \
-                                       0x0001FFFF
-
-/*  Interrupt numbers for each interrupt level at which only one interrupt was configured:  */
-/*#define XCHAL_INTLEVEL1_NUM          ...more than one interrupt at this level...*/
-/*#define XCHAL_INTLEVEL2_NUM          ...more than one interrupt at this level...*/
-/*#define XCHAL_INTLEVEL3_NUM          ...more than one interrupt at this level...*/
-
-/*  Level of each interrupt:  */
-#define XCHAL_INT0_LEVEL               1
-#define XCHAL_INT1_LEVEL               2
-#define XCHAL_INT2_LEVEL               3
-#define XCHAL_INT3_LEVEL               1
-#define XCHAL_INT4_LEVEL               1
-#define XCHAL_INT5_LEVEL               1
-#define XCHAL_INT6_LEVEL               1
-#define XCHAL_INT7_LEVEL               1
-#define XCHAL_INT8_LEVEL               2
-#define XCHAL_INT9_LEVEL               3
-#define XCHAL_INT10_LEVEL              1
-#define XCHAL_INT11_LEVEL              2
-#define XCHAL_INT12_LEVEL              3
-#define XCHAL_INT13_LEVEL              1
-#define XCHAL_INT14_LEVEL              1
-#define XCHAL_INT15_LEVEL              2
-#define XCHAL_INT16_LEVEL              3
-#define XCHAL_INT17_LEVEL              0
-#define XCHAL_INT18_LEVEL              0
-#define XCHAL_INT19_LEVEL              0
-#define XCHAL_INT20_LEVEL              0
-#define XCHAL_INT21_LEVEL              0
-#define XCHAL_INT22_LEVEL              0
-#define XCHAL_INT23_LEVEL              0
-#define XCHAL_INT24_LEVEL              0
-#define XCHAL_INT25_LEVEL              0
-#define XCHAL_INT26_LEVEL              0
-#define XCHAL_INT27_LEVEL              0
-#define XCHAL_INT28_LEVEL              0
-#define XCHAL_INT29_LEVEL              0
-#define XCHAL_INT30_LEVEL              0
-#define XCHAL_INT31_LEVEL              0
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_INT_LEVELS               1       XCHAL_SEP \
-                                       2       XCHAL_SEP \
-                                       3       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       2       XCHAL_SEP \
-                                       3       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       2       XCHAL_SEP \
-                                       3       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       1       XCHAL_SEP \
-                                       2       XCHAL_SEP \
-                                       3       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0       XCHAL_SEP \
-                                       0
-
-/*  Type of each interrupt:  */
-#define XCHAL_INT0_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT1_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT2_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT3_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT4_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT5_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT6_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL
-#define XCHAL_INT7_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT8_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT9_TYPE        XTHAL_INTTYPE_EXTERN_EDGE
-#define XCHAL_INT10_TYPE       XTHAL_INTTYPE_TIMER
-#define XCHAL_INT11_TYPE       XTHAL_INTTYPE_TIMER
-#define XCHAL_INT12_TYPE       XTHAL_INTTYPE_TIMER
-#define XCHAL_INT13_TYPE       XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT14_TYPE       XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT15_TYPE       XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT16_TYPE       XTHAL_INTTYPE_SOFTWARE
-#define XCHAL_INT17_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT18_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT19_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT20_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT21_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT22_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT23_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT24_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT25_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT26_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT27_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT28_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT29_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT30_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-#define XCHAL_INT31_TYPE       XTHAL_INTTYPE_UNCONFIGURED
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_INT_TYPES                XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_LEVEL      XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
-                               XTHAL_INTTYPE_EXTERN_EDGE       XCHAL_SEP \
-                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
-                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
-                               XTHAL_INTTYPE_TIMER             XCHAL_SEP \
-                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
-                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
-                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
-                               XTHAL_INTTYPE_SOFTWARE          XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED      XCHAL_SEP \
-                               XTHAL_INTTYPE_UNCONFIGURED
-
-/*  Masks of interrupts for each type of interrupt:  */
-#define XCHAL_INTTYPE_MASK_UNCONFIGURED        0xFFFE0000
-#define XCHAL_INTTYPE_MASK_SOFTWARE    0x0001E000
-#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
-#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL        0x0000007F
-#define XCHAL_INTTYPE_MASK_TIMER       0x00001C00
-#define XCHAL_INTTYPE_MASK_NMI         0x00000000
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_INTTYPE_MASKS            0xFFFE0000      XCHAL_SEP \
-                                       0x0001E000      XCHAL_SEP \
-                                       0x00000380      XCHAL_SEP \
-                                       0x0000007F      XCHAL_SEP \
-                                       0x00001C00      XCHAL_SEP \
-                                       0x00000000
-
-/*  Interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned  */
-#define XCHAL_TIMER0_INTERRUPT 10
-#define XCHAL_TIMER1_INTERRUPT 11
-#define XCHAL_TIMER2_INTERRUPT 12
-#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
-/*  As an array of entries (eg. for C constant arrays):  */
-#define XCHAL_TIMER_INTERRUPTS 10      XCHAL_SEP \
-                               11      XCHAL_SEP \
-                               12      XCHAL_SEP \
-                               XTHAL_TIMER_UNCONFIGURED
-
-/*  Indexing macros:  */
-#define _XCHAL_INTLEVEL_MASK(n)                XCHAL_INTLEVEL ## n ## _MASK
-#define XCHAL_INTLEVEL_MASK(n)         _XCHAL_INTLEVEL_MASK(n)         /* n = 0 .. 15 */
-#define _XCHAL_INTLEVEL_ANDBELOWMASK(n)        XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK
-#define XCHAL_INTLEVEL_ANDBELOW_MASK(n)        _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */
-#define _XCHAL_INT_LEVEL(n)            XCHAL_INT ## n ## _LEVEL
-#define XCHAL_INT_LEVEL(n)             _XCHAL_INT_LEVEL(n)             /* n = 0 .. 31 */
-#define _XCHAL_INT_TYPE(n)             XCHAL_INT ## n ## _TYPE
-#define XCHAL_INT_TYPE(n)              _XCHAL_INT_TYPE(n)              /* n = 0 .. 31 */
-#define _XCHAL_TIMER_INTERRUPT(n)      XCHAL_TIMER ## n ## _INTERRUPT
-#define XCHAL_TIMER_INTERRUPT(n)       _XCHAL_TIMER_INTERRUPT(n)       /* n = 0 .. 3 */
-
-
-
-/*
- *  External interrupt vectors/levels.
- *  These macros describe how Xtensa processor interrupt numbers
- *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
- *  map to external BInterrupt<n> pins, for those interrupts
- *  configured as external (level-triggered, edge-triggered, or NMI).
- *  See the Xtensa processor databook for more details.
- */
-
-/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */
-#define XCHAL_EXTINT0_NUM              0       /* (intlevel 1) */
-#define XCHAL_EXTINT1_NUM              1       /* (intlevel 2) */
-#define XCHAL_EXTINT2_NUM              2       /* (intlevel 3) */
-#define XCHAL_EXTINT3_NUM              3       /* (intlevel 1) */
-#define XCHAL_EXTINT4_NUM              4       /* (intlevel 1) */
-#define XCHAL_EXTINT5_NUM              5       /* (intlevel 1) */
-#define XCHAL_EXTINT6_NUM              6       /* (intlevel 1) */
-#define XCHAL_EXTINT7_NUM              7       /* (intlevel 1) */
-#define XCHAL_EXTINT8_NUM              8       /* (intlevel 2) */
-#define XCHAL_EXTINT9_NUM              9       /* (intlevel 3) */
-
-/*  Corresponding interrupt masks:  */
-#define XCHAL_EXTINT0_MASK             0x00000001
-#define XCHAL_EXTINT1_MASK             0x00000002
-#define XCHAL_EXTINT2_MASK             0x00000004
-#define XCHAL_EXTINT3_MASK             0x00000008
-#define XCHAL_EXTINT4_MASK             0x00000010
-#define XCHAL_EXTINT5_MASK             0x00000020
-#define XCHAL_EXTINT6_MASK             0x00000040
-#define XCHAL_EXTINT7_MASK             0x00000080
-#define XCHAL_EXTINT8_MASK             0x00000100
-#define XCHAL_EXTINT9_MASK             0x00000200
-
-/*  Core config interrupt levels mapped to each external interrupt:  */
-#define XCHAL_EXTINT0_LEVEL            1       /* (int number 0) */
-#define XCHAL_EXTINT1_LEVEL            2       /* (int number 1) */
-#define XCHAL_EXTINT2_LEVEL            3       /* (int number 2) */
-#define XCHAL_EXTINT3_LEVEL            1       /* (int number 3) */
-#define XCHAL_EXTINT4_LEVEL            1       /* (int number 4) */
-#define XCHAL_EXTINT5_LEVEL            1       /* (int number 5) */
-#define XCHAL_EXTINT6_LEVEL            1       /* (int number 6) */
-#define XCHAL_EXTINT7_LEVEL            1       /* (int number 7) */
-#define XCHAL_EXTINT8_LEVEL            2       /* (int number 8) */
-#define XCHAL_EXTINT9_LEVEL            3       /* (int number 9) */
-
-
-/*----------------------------------------------------------------------
-                       EXCEPTIONS and VECTORS
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_EXCEPTIONS          1       /* 1 if exception option configured, 0 otherwise */
-
-#define XCHAL_XEA_VERSION              2       /* Xtensa Exception Architecture number: 1 for XEA1 (old), 2 for XEA2 (new) */
-#define XCHAL_HAVE_XEA1                        0       /* 1 if XEA1, 0 otherwise */
-#define XCHAL_HAVE_XEA2                        1       /* 1 if XEA2, 0 otherwise */
-/*  For backward compatibility ONLY -- DO NOT USE (will be removed in future release):  */
-#define XCHAL_HAVE_OLD_EXC_ARCH                XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */
-#define XCHAL_HAVE_EXCM                        XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */
-
-#define XCHAL_RESET_VECTOR_VADDR       0xFE000020
-#define XCHAL_RESET_VECTOR_PADDR       0xFE000020
-#define XCHAL_USER_VECTOR_VADDR                0xD0000220
-#define XCHAL_PROGRAMEXC_VECTOR_VADDR  XCHAL_USER_VECTOR_VADDR         /* for backward compatibility */
-#define XCHAL_USEREXC_VECTOR_VADDR     XCHAL_USER_VECTOR_VADDR         /* for backward compatibility */
-#define XCHAL_USER_VECTOR_PADDR                0x00000220
-#define XCHAL_PROGRAMEXC_VECTOR_PADDR  XCHAL_USER_VECTOR_PADDR         /* for backward compatibility */
-#define XCHAL_USEREXC_VECTOR_PADDR     XCHAL_USER_VECTOR_PADDR         /* for backward compatibility */
-#define XCHAL_KERNEL_VECTOR_VADDR      0xD0000200
-#define XCHAL_STACKEDEXC_VECTOR_VADDR  XCHAL_KERNEL_VECTOR_VADDR       /* for backward compatibility */
-#define XCHAL_KERNELEXC_VECTOR_VADDR   XCHAL_KERNEL_VECTOR_VADDR       /* for backward compatibility */
-#define XCHAL_KERNEL_VECTOR_PADDR      0x00000200
-#define XCHAL_STACKEDEXC_VECTOR_PADDR  XCHAL_KERNEL_VECTOR_PADDR       /* for backward compatibility */
-#define XCHAL_KERNELEXC_VECTOR_PADDR   XCHAL_KERNEL_VECTOR_PADDR       /* for backward compatibility */
-#define XCHAL_DOUBLEEXC_VECTOR_VADDR   0xD0000290
-#define XCHAL_DOUBLEEXC_VECTOR_PADDR   0x00000290
-#define XCHAL_WINDOW_VECTORS_VADDR     0xD0000000
-#define XCHAL_WINDOW_VECTORS_PADDR     0x00000000
-#define XCHAL_INTLEVEL2_VECTOR_VADDR   0xD0000240
-#define XCHAL_INTLEVEL2_VECTOR_PADDR   0x00000240
-#define XCHAL_INTLEVEL3_VECTOR_VADDR   0xD0000250
-#define XCHAL_INTLEVEL3_VECTOR_PADDR   0x00000250
-#define XCHAL_INTLEVEL4_VECTOR_VADDR   0xFE000520
-#define XCHAL_INTLEVEL4_VECTOR_PADDR   0xFE000520
-#define XCHAL_DEBUG_VECTOR_VADDR       XCHAL_INTLEVEL4_VECTOR_VADDR
-#define XCHAL_DEBUG_VECTOR_PADDR       XCHAL_INTLEVEL4_VECTOR_PADDR
-
-/*  Indexing macros:  */
-#define _XCHAL_INTLEVEL_VECTOR_VADDR(n)                XCHAL_INTLEVEL ## n ## _VECTOR_VADDR
-#define XCHAL_INTLEVEL_VECTOR_VADDR(n)         _XCHAL_INTLEVEL_VECTOR_VADDR(n)         /* n = 0 .. 15 */
-
-/*
- *  General Exception Causes
- *  (values of EXCCAUSE special register set by general exceptions,
- *   which vector to the user, kernel, or double-exception vectors):
- */
-#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION             0       /* Illegal Instruction (IllegalInstruction) */
-#define XCHAL_EXCCAUSE_SYSTEM_CALL                     1       /* System Call (SystemCall) */
-#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR         2       /* Instruction Fetch Error (InstructionFetchError) */
-#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR                        3       /* Load Store Error (LoadStoreError) */
-#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT                        4       /* Level 1 Interrupt (Level1Interrupt) */
-#define XCHAL_EXCCAUSE_ALLOCA                          5       /* Stack Extension Assist (Alloca) */
-#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO          6       /* Integer Divide by Zero (IntegerDivideByZero) */
-#define XCHAL_EXCCAUSE_SPECULATION                     7       /* Speculation (Speculation) */
-#define XCHAL_EXCCAUSE_PRIVILEGED                      8       /* Privileged Instruction (Privileged) */
-#define XCHAL_EXCCAUSE_UNALIGNED                       9       /* Unaligned Load Store (Unaligned) */
-#define XCHAL_EXCCAUSE_ITLB_MISS                       16      /* ITlb Miss Exception (ITlbMiss) */
-#define XCHAL_EXCCAUSE_ITLB_MULTIHIT                   17      /* ITlb Mutltihit Exception (ITlbMultihit) */
-#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE                  18      /* ITlb Privilege Exception (ITlbPrivilege) */
-#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION           19      /* ITlb Size Restriction Exception (ITlbSizeRestriction) */
-#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE           20      /* Fetch Cache Attribute Exception (FetchCacheAttribute) */
-#define XCHAL_EXCCAUSE_DTLB_MISS                       24      /* DTlb Miss Exception (DTlbMiss) */
-#define XCHAL_EXCCAUSE_DTLB_MULTIHIT                   25      /* DTlb Multihit Exception (DTlbMultihit) */
-#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE                  26      /* DTlb Privilege Exception (DTlbPrivilege) */
-#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION           27      /* DTlb Size Restriction Exception (DTlbSizeRestriction) */
-#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE            28      /* Load Cache Attribute Exception (LoadCacheAttribute) */
-#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE           29      /* Store Cache Attribute Exception (StoreCacheAttribute) */
-#define XCHAL_EXCCAUSE_FLOATING_POINT                  40      /* Floating Point Exception (FloatingPoint) */
-
-
-
-/*----------------------------------------------------------------------
-                               TIMERS
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_CCOUNT              1       /* 1 if have CCOUNT, 0 otherwise */
-/*#define XCHAL_HAVE_TIMERS            XCHAL_HAVE_CCOUNT*/
-#define XCHAL_NUM_TIMERS               3       /* number of CCOMPAREn regs */
-
-
-
-/*----------------------------------------------------------------------
-                               DEBUG
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_DEBUG               1       /* 1 if debug option configured, 0 otherwise */
-#define XCHAL_HAVE_OCD                 1       /* 1 if OnChipDebug option configured, 0 otherwise */
-#define XCHAL_NUM_IBREAK               2       /* number of IBREAKn regs */
-#define XCHAL_NUM_DBREAK               2       /* number of DBREAKn regs */
-#define XCHAL_DEBUGLEVEL               4       /* debug interrupt level */
-/*DebugExternalInterrupt               0               0|1*/
-/*DebugUseDIRArray                     0               0|1*/
-
-
-
-
-/*----------------------------------------------------------------------
-                       COPROCESSORS and EXTRA STATE
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_CP                  0       /* 1 if coprocessor option configured (CPENABLE present) */
-#define XCHAL_CP_MAXCFG                        0       /* max allowed cp id plus one (per cfg) */
-
-#include <xtensa/config/tie.h>
-
-
-
-
-/*----------------------------------------------------------------------
-                       INTERNAL I/D RAM/ROMs and XLMI
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_NUM_INSTROM              0       /* number of core instruction ROMs configured */
-#define XCHAL_NUM_INSTRAM              0       /* number of core instruction RAMs configured */
-#define XCHAL_NUM_DATAROM              0       /* number of core data ROMs configured */
-#define XCHAL_NUM_DATARAM              0       /* number of core data RAMs configured */
-#define XCHAL_NUM_XLMI                 0       /* number of core XLMI ports configured */
-#define  XCHAL_NUM_IROM                        XCHAL_NUM_INSTROM       /* (DEPRECATED) */
-#define  XCHAL_NUM_IRAM                        XCHAL_NUM_INSTRAM       /* (DEPRECATED) */
-#define  XCHAL_NUM_DROM                        XCHAL_NUM_DATAROM       /* (DEPRECATED) */
-#define  XCHAL_NUM_DRAM                        XCHAL_NUM_DATARAM       /* (DEPRECATED) */
-
-
-
-/*----------------------------------------------------------------------
-                               CACHE
-  ----------------------------------------------------------------------*/
-
-/*  Size of the cache lines in log2(bytes):  */
-#define XCHAL_ICACHE_LINEWIDTH         4
-#define XCHAL_DCACHE_LINEWIDTH         4
-/*  Size of the cache lines in bytes:  */
-#define XCHAL_ICACHE_LINESIZE          16
-#define XCHAL_DCACHE_LINESIZE          16
-/*  Max for both I-cache and D-cache (used for general alignment):  */
-#define XCHAL_CACHE_LINEWIDTH_MAX      4
-#define XCHAL_CACHE_LINESIZE_MAX       16
-
-/*  Number of cache sets in log2(lines per way):  */
-#define XCHAL_ICACHE_SETWIDTH          8
-#define XCHAL_DCACHE_SETWIDTH          8
-/*  Max for both I-cache and D-cache (used for general cache-coherency page alignment):  */
-#define XCHAL_CACHE_SETWIDTH_MAX       8
-#define XCHAL_CACHE_SETSIZE_MAX                256
-
-/*  Cache set associativity (number of ways):  */
-#define XCHAL_ICACHE_WAYS              2
-#define XCHAL_DCACHE_WAYS              2
-
-/*  Size of the caches in bytes (ways * 2^(linewidth + setwidth)):  */
-#define XCHAL_ICACHE_SIZE              8192
-#define XCHAL_DCACHE_SIZE              8192
-
-/*  Cache features:  */
-#define XCHAL_DCACHE_IS_WRITEBACK      0
-/*  Whether cache locking feature is available:  */
-#define XCHAL_ICACHE_LINE_LOCKABLE     0
-#define XCHAL_DCACHE_LINE_LOCKABLE     0
-
-/*  Number of (encoded) cache attribute bits:  */
-#define XCHAL_CA_BITS                  4       /* number of bits needed to hold cache attribute encoding */
-/*  (The number of access mode bits (decoded cache attribute bits) is defined by the architecture; see xtensa/hal.h?)  */
-
-
-/*  Cache Attribute encodings -- lists of access modes for each cache attribute:  */
-#define XCHAL_FCA_LIST         XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_BYPASS        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_BYPASS        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_CACHED        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_CACHED        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_CACHED        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_CACHED        XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_FAM_EXCEPTION
-#define XCHAL_LCA_LIST         XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_BYPASSG       XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_BYPASSG       XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_CACHED        XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_CACHED        XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_NACACHED      XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_NACACHED      XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_ISOLATE       XCHAL_SEP \
-                               XTHAL_LAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_LAM_CACHED
-#define XCHAL_SCA_LIST         XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_BYPASS        XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_WRITETHRU     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_WRITETHRU     XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_ISOLATE       XCHAL_SEP \
-                               XTHAL_SAM_EXCEPTION     XCHAL_SEP \
-                               XTHAL_SAM_WRITETHRU
-
-/*  Test:
-       read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
-       read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
-       all:       0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
-       fault:     0 + 2 + 4 + 6 + 8 + 10 + 12 + 14
-       r/w/x cached:
-       r/w/x dcached:
-       I-bypass:  1 + 3
-
-       load guard bit set: 1 + 3
-       load guard bit clr: 0 + 2 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
-       hit-cache r/w/x: 7 + 11
-
-       fams: 5
-       fams: 0 / 6 / 18 / 1 / 2
-       fams: Bypass / Isolate / Cached / Exception / NACached
-
-        MMU okay:  yes
-*/
-
-
-/*----------------------------------------------------------------------
-                               MMU
-  ----------------------------------------------------------------------*/
-
-/*
- *  General notes on MMU parameters.
- *
- *  Terminology:
- *     ASID = address-space ID (acts as an "extension" of virtual addresses)
- *     VPN  = virtual page number
- *     PPN  = physical page number
- *     CA   = encoded cache attribute (access modes)
- *     TLB  = translation look-aside buffer (term is stretched somewhat here)
- *     I    = instruction (fetch accesses)
- *     D    = data (load and store accesses)
- *     way  = each TLB (ITLB and DTLB) consists of a number of "ways"
- *             that simultaneously match the virtual address of an access;
- *             a TLB successfully translates a virtual address if exactly
- *             one way matches the vaddr; if none match, it is a miss;
- *             if multiple match, one gets a "multihit" exception;
- *             each way can be independently configured in terms of number of
- *             entries, page sizes, which fields are writable or constant, etc.
- *     set  = group of contiguous ways with exactly identical parameters
- *     ARF  = auto-refill; hardware services a 1st-level miss by loading a PTE
- *             from the page table and storing it in one of the auto-refill ways;
- *             if this PTE load also misses, a miss exception is posted for s/w.
- *     min-wired = a "min-wired" way can be used to map a single (minimum-sized)
- *             page arbitrarily under program control; it has a single entry,
- *             is non-auto-refill (some other way(s) must be auto-refill),
- *             all its fields (VPN, PPN, ASID, CA) are all writable, and it
- *             supports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current
- *             restriction is that this be the only page size it supports).
- *
- *  TLB way entries are virtually indexed.
- *  TLB ways that support multiple page sizes:
- *     - must have all writable VPN and PPN fields;
- *     - can only use one page size at any given time (eg. setup at startup),
- *       selected by the respective ITLBCFG or DTLBCFG special register,
- *       whose bits n*4+3 .. n*4 index the list of page sizes for way n
- *       (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n);
- *       this list may be sparse for auto-refill ways because auto-refill
- *       ways have independent lists of supported page sizes sharing a
- *       common encoding with PTE entries; the encoding is the index into
- *       this list; unsupported sizes for a given way are zero in the list;
- *       selecting unsupported sizes results in undefined hardware behaviour;
- *     - is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition).
- */
-
-#define XCHAL_HAVE_CACHEATTR           0       /* 1 if CACHEATTR register present, 0 if TLBs present instead */
-#define XCHAL_HAVE_TLBS                        1       /* 1 if TLBs present, 0 if CACHEATTR present instead */
-#define XCHAL_HAVE_MMU                 XCHAL_HAVE_TLBS /* (DEPRECATED; use XCHAL_HAVE_TLBS instead; will be removed in future release) */
-#define XCHAL_HAVE_SPANNING_WAY                0       /* 1 if single way maps entire virtual address space in I+D */
-#define XCHAL_HAVE_IDENTITY_MAP                0       /* 1 if virtual addr == physical addr always, 0 otherwise */
-#define XCHAL_HAVE_MIMIC_CACHEATTR     0       /* 1 if have MMU that mimics a CACHEATTR config (CaMMU) */
-#define XCHAL_HAVE_XLT_CACHEATTR       0       /* 1 if have MMU that mimics a CACHEATTR config, but with translation (CaXltMMU) */
-
-#define XCHAL_MMU_ASID_BITS            8       /* number of bits in ASIDs (address space IDs) */
-#define XCHAL_MMU_ASID_INVALID         0       /* ASID value indicating invalid address space */
-#define XCHAL_MMU_ASID_KERNEL          1       /* ASID value indicating kernel (ring 0) address space */
-#define XCHAL_MMU_RINGS                        4       /* number of rings supported (1..4) */
-#define XCHAL_MMU_RING_BITS            2       /* number of bits needed to hold ring number */
-#define XCHAL_MMU_SR_BITS              0       /* number of size-restriction bits supported */
-#define XCHAL_MMU_CA_BITS              4       /* number of bits needed to hold cache attribute encoding */
-#define XCHAL_MMU_MAX_PTE_PAGE_SIZE    12      /* max page size in a PTE structure (log2) */
-#define XCHAL_MMU_MIN_PTE_PAGE_SIZE    12      /* min page size in a PTE structure (log2) */
-
-
-/***  Instruction TLB:  ***/
-
-#define XCHAL_ITLB_WAY_BITS            3       /* number of bits holding the ways */
-#define XCHAL_ITLB_WAYS                        7       /* number of ways (n-way set-associative TLB) */
-#define XCHAL_ITLB_ARF_WAYS            4       /* number of auto-refill ways */
-#define XCHAL_ITLB_SETS                        4       /* number of sets (groups of ways with identical settings) */
-
-/*  Way set to which each way belongs:  */
-#define XCHAL_ITLB_WAY0_SET            0
-#define XCHAL_ITLB_WAY1_SET            0
-#define XCHAL_ITLB_WAY2_SET            0
-#define XCHAL_ITLB_WAY3_SET            0
-#define XCHAL_ITLB_WAY4_SET            1
-#define XCHAL_ITLB_WAY5_SET            2
-#define XCHAL_ITLB_WAY6_SET            3
-
-/*  Ways sets that are used by hardware auto-refill (ARF):  */
-#define XCHAL_ITLB_ARF_SETS            1       /* number of auto-refill sets */
-#define XCHAL_ITLB_ARF_SET0            0       /* index of n'th auto-refill set */
-
-/*  Way sets that are "min-wired" (see terminology comment above):  */
-#define XCHAL_ITLB_MINWIRED_SETS       0       /* number of "min-wired" sets */
-
-
-/*  ITLB way set 0 (group of ways 0 thru 3):  */
-#define XCHAL_ITLB_SET0_WAY                    0       /* index of first way in this way set */
-#define XCHAL_ITLB_SET0_WAYS                   4       /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET0_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET0_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET0_ARF                    1       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET0_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET0_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET0_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET0_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET0_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/*  ITLB way set 1 (group of ways 4 thru 4):  */
-#define XCHAL_ITLB_SET1_WAY                    4       /* index of first way in this way set */
-#define XCHAL_ITLB_SET1_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET1_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET1_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET1_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET1_PAGESIZES              4       /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET1_PAGESZ_BITS            2       /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MIN                20      /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MAX                26      /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET1_PAGESZ_LOG2_LIST       20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26       /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET1_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET1_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET1_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/*  ITLB way set 2 (group of ways 5 thru 5):  */
-#define XCHAL_ITLB_SET2_WAY                    5       /* index of first way in this way set */
-#define XCHAL_ITLB_SET2_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET2_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET2_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET2_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET2_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET2_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MIN                27      /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MAX                27      /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET2_PAGESZ_LOG2_LIST       27      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET2_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_VPN_CONSTMASK          0xF0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_PPN_CONSTMASK          0xF8000000      /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET2_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET2_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/*  Constant ASID values for each entry of ITLB way set 2 (because ASID_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET2_E0_ASID_CONST          0x01
-#define XCHAL_ITLB_SET2_E1_ASID_CONST          0x01
-/*  Constant VPN values for each entry of ITLB way set 2 (because VPN_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET2_E0_VPN_CONST           0xD0000000
-#define XCHAL_ITLB_SET2_E1_VPN_CONST           0xD8000000
-/*  Constant PPN values for each entry of ITLB way set 2 (because PPN_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET2_E0_PPN_CONST           0x00000000
-#define XCHAL_ITLB_SET2_E1_PPN_CONST           0x00000000
-/*  Constant CA values for each entry of ITLB way set 2 (because CA_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET2_E0_CA_CONST            0x07
-#define XCHAL_ITLB_SET2_E1_CA_CONST            0x03
-
-/*  ITLB way set 3 (group of ways 6 thru 6):  */
-#define XCHAL_ITLB_SET3_WAY                    6       /* index of first way in this way set */
-#define XCHAL_ITLB_SET3_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_ITLB_SET3_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
-#define XCHAL_ITLB_SET3_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
-#define XCHAL_ITLB_SET3_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_ITLB_SET3_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_ITLB_SET3_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MIN                28      /* log2(minimum supported page size) */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MAX                28      /* log2(maximum supported page size) */
-#define XCHAL_ITLB_SET3_PAGESZ_LOG2_LIST       28      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_ITLB_SET3_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_VPN_CONSTMASK          0xE0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_PPN_CONSTMASK          0xF0000000      /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
-#define XCHAL_ITLB_SET3_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_ITLB_SET3_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/*  Constant ASID values for each entry of ITLB way set 3 (because ASID_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET3_E0_ASID_CONST          0x01
-#define XCHAL_ITLB_SET3_E1_ASID_CONST          0x01
-/*  Constant VPN values for each entry of ITLB way set 3 (because VPN_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET3_E0_VPN_CONST           0xE0000000
-#define XCHAL_ITLB_SET3_E1_VPN_CONST           0xF0000000
-/*  Constant PPN values for each entry of ITLB way set 3 (because PPN_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET3_E0_PPN_CONST           0xF0000000
-#define XCHAL_ITLB_SET3_E1_PPN_CONST           0xF0000000
-/*  Constant CA values for each entry of ITLB way set 3 (because CA_CONSTMASK is non-zero):  */
-#define XCHAL_ITLB_SET3_E0_CA_CONST            0x07
-#define XCHAL_ITLB_SET3_E1_CA_CONST            0x03
-
-/*  Indexing macros:  */
-#define _XCHAL_ITLB_SET(n,_what)       XCHAL_ITLB_SET ## n ## _what
-#define XCHAL_ITLB_SET(n,what)         _XCHAL_ITLB_SET(n, _ ## what )
-#define _XCHAL_ITLB_SET_E(n,i,_what)   XCHAL_ITLB_SET ## n ## _E ## i ## _what
-#define XCHAL_ITLB_SET_E(n,i,what)     _XCHAL_ITLB_SET_E(n,i, _ ## what )
-/*
- *  Example use:  XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES)
- *     to get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
- */
-
-
-/***  Data TLB:  ***/
-
-#define XCHAL_DTLB_WAY_BITS            4       /* number of bits holding the ways */
-#define XCHAL_DTLB_WAYS                        10      /* number of ways (n-way set-associative TLB) */
-#define XCHAL_DTLB_ARF_WAYS            4       /* number of auto-refill ways */
-#define XCHAL_DTLB_SETS                        5       /* number of sets (groups of ways with identical settings) */
-
-/*  Way set to which each way belongs:  */
-#define XCHAL_DTLB_WAY0_SET            0
-#define XCHAL_DTLB_WAY1_SET            0
-#define XCHAL_DTLB_WAY2_SET            0
-#define XCHAL_DTLB_WAY3_SET            0
-#define XCHAL_DTLB_WAY4_SET            1
-#define XCHAL_DTLB_WAY5_SET            2
-#define XCHAL_DTLB_WAY6_SET            3
-#define XCHAL_DTLB_WAY7_SET            4
-#define XCHAL_DTLB_WAY8_SET            4
-#define XCHAL_DTLB_WAY9_SET            4
-
-/*  Ways sets that are used by hardware auto-refill (ARF):  */
-#define XCHAL_DTLB_ARF_SETS            1       /* number of auto-refill sets */
-#define XCHAL_DTLB_ARF_SET0            0       /* index of n'th auto-refill set */
-
-/*  Way sets that are "min-wired" (see terminology comment above):  */
-#define XCHAL_DTLB_MINWIRED_SETS       1       /* number of "min-wired" sets */
-#define XCHAL_DTLB_MINWIRED_SET0       4       /* index of n'th "min-wired" set */
-
-
-/*  DTLB way set 0 (group of ways 0 thru 3):  */
-#define XCHAL_DTLB_SET0_WAY                    0       /* index of first way in this way set */
-#define XCHAL_DTLB_SET0_WAYS                   4       /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET0_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET0_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET0_ARF                    1       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET0_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET0_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET0_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET0_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET0_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/*  DTLB way set 1 (group of ways 4 thru 4):  */
-#define XCHAL_DTLB_SET1_WAY                    4       /* index of first way in this way set */
-#define XCHAL_DTLB_SET1_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET1_ENTRIES_LOG2           2       /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET1_ENTRIES                        4       /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET1_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET1_PAGESIZES              4       /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET1_PAGESZ_BITS            2       /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MIN                20      /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MAX                26      /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET1_PAGESZ_LOG2_LIST       20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26       /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET1_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET1_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET1_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/*  DTLB way set 2 (group of ways 5 thru 5):  */
-#define XCHAL_DTLB_SET2_WAY                    5       /* index of first way in this way set */
-#define XCHAL_DTLB_SET2_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET2_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET2_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET2_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET2_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET2_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MIN                27      /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MAX                27      /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET2_PAGESZ_LOG2_LIST       27      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET2_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_VPN_CONSTMASK          0xF0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_PPN_CONSTMASK          0xF8000000      /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET2_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET2_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/*  Constant ASID values for each entry of DTLB way set 2 (because ASID_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET2_E0_ASID_CONST          0x01
-#define XCHAL_DTLB_SET2_E1_ASID_CONST          0x01
-/*  Constant VPN values for each entry of DTLB way set 2 (because VPN_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET2_E0_VPN_CONST           0xD0000000
-#define XCHAL_DTLB_SET2_E1_VPN_CONST           0xD8000000
-/*  Constant PPN values for each entry of DTLB way set 2 (because PPN_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET2_E0_PPN_CONST           0x00000000
-#define XCHAL_DTLB_SET2_E1_PPN_CONST           0x00000000
-/*  Constant CA values for each entry of DTLB way set 2 (because CA_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET2_E0_CA_CONST            0x07
-#define XCHAL_DTLB_SET2_E1_CA_CONST            0x03
-
-/*  DTLB way set 3 (group of ways 6 thru 6):  */
-#define XCHAL_DTLB_SET3_WAY                    6       /* index of first way in this way set */
-#define XCHAL_DTLB_SET3_WAYS                   1       /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET3_ENTRIES_LOG2           1       /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET3_ENTRIES                        2       /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET3_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET3_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET3_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MIN                28      /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MAX                28      /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET3_PAGESZ_LOG2_LIST       28      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET3_ASID_CONSTMASK         0xFF    /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_VPN_CONSTMASK          0xE0000000      /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_PPN_CONSTMASK          0xF0000000      /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_CA_CONSTMASK           0x0000000F      /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET3_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET3_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-/*  Constant ASID values for each entry of DTLB way set 3 (because ASID_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET3_E0_ASID_CONST          0x01
-#define XCHAL_DTLB_SET3_E1_ASID_CONST          0x01
-/*  Constant VPN values for each entry of DTLB way set 3 (because VPN_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET3_E0_VPN_CONST           0xE0000000
-#define XCHAL_DTLB_SET3_E1_VPN_CONST           0xF0000000
-/*  Constant PPN values for each entry of DTLB way set 3 (because PPN_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET3_E0_PPN_CONST           0xF0000000
-#define XCHAL_DTLB_SET3_E1_PPN_CONST           0xF0000000
-/*  Constant CA values for each entry of DTLB way set 3 (because CA_CONSTMASK is non-zero):  */
-#define XCHAL_DTLB_SET3_E0_CA_CONST            0x07
-#define XCHAL_DTLB_SET3_E1_CA_CONST            0x03
-
-/*  DTLB way set 4 (group of ways 7 thru 9):  */
-#define XCHAL_DTLB_SET4_WAY                    7       /* index of first way in this way set */
-#define XCHAL_DTLB_SET4_WAYS                   3       /* number of (contiguous) ways in this way set */
-#define XCHAL_DTLB_SET4_ENTRIES_LOG2           0       /* log2(number of entries in this way) */
-#define XCHAL_DTLB_SET4_ENTRIES                        1       /* number of entries in this way (always a power of 2) */
-#define XCHAL_DTLB_SET4_ARF                    0       /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
-#define XCHAL_DTLB_SET4_PAGESIZES              1       /* number of supported page sizes in this way */
-#define XCHAL_DTLB_SET4_PAGESZ_BITS            0       /* number of bits to encode the page size */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MIN                12      /* log2(minimum supported page size) */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MAX                12      /* log2(maximum supported page size) */
-#define XCHAL_DTLB_SET4_PAGESZ_LOG2_LIST       12      /* list of log2(page size)s, separated by XCHAL_SEP;
-                                                          2^PAGESZ_BITS entries in list, unsupported entries are zero */
-#define XCHAL_DTLB_SET4_ASID_CONSTMASK         0       /* constant ASID bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_VPN_CONSTMASK          0       /* constant VPN bits, not including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_PPN_CONSTMASK          0       /* constant PPN bits, including entry index bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_CA_CONSTMASK           0       /* constant CA bits; 0 if all writable */
-#define XCHAL_DTLB_SET4_ASID_RESET             0       /* 1 if ASID reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_VPN_RESET              0       /* 1 if VPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_PPN_RESET              0       /* 1 if PPN reset values defined (and all writable); 0 otherwise */
-#define XCHAL_DTLB_SET4_CA_RESET               0       /* 1 if CA reset values defined (and all writable); 0 otherwise */
-
-/*  Indexing macros:  */
-#define _XCHAL_DTLB_SET(n,_what)       XCHAL_DTLB_SET ## n ## _what
-#define XCHAL_DTLB_SET(n,what)         _XCHAL_DTLB_SET(n, _ ## what )
-#define _XCHAL_DTLB_SET_E(n,i,_what)   XCHAL_DTLB_SET ## n ## _E ## i ## _what
-#define XCHAL_DTLB_SET_E(n,i,what)     _XCHAL_DTLB_SET_E(n,i, _ ## what )
-/*
- *  Example use:  XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES)
- *     to get the value of XCHAL_DTLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
- */
-
-
-/*
- *  Determine whether we have a full MMU (with Page Table and Protection)
- *  usable for an MMU-based OS:
- */
-#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2
-# define XCHAL_HAVE_PTP_MMU            1       /* have full MMU (with page table [autorefill] and protection) */
-#else
-# define XCHAL_HAVE_PTP_MMU            0       /* don't have full MMU */
-#endif
-
-/*
- *  For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings:
- */
-#if XCHAL_HAVE_PTP_MMU
-#define XCHAL_KSEG_CACHED_VADDR                0xD0000000      /* virt.addr of kernel RAM cached static map */
-#define XCHAL_KSEG_CACHED_PADDR                0x00000000      /* phys.addr of kseg_cached */
-#define XCHAL_KSEG_CACHED_SIZE         0x08000000      /* size in bytes of kseg_cached (assumed power of 2!!!) */
-#define XCHAL_KSEG_BYPASS_VADDR                0xD8000000      /* virt.addr of kernel RAM bypass (uncached) static map */
-#define XCHAL_KSEG_BYPASS_PADDR                0x00000000      /* phys.addr of kseg_bypass */
-#define XCHAL_KSEG_BYPASS_SIZE         0x08000000      /* size in bytes of kseg_bypass (assumed power of 2!!!) */
-
-#define XCHAL_KIO_CACHED_VADDR         0xE0000000      /* virt.addr of kernel I/O cached static map */
-#define XCHAL_KIO_CACHED_PADDR         0xF0000000      /* phys.addr of kio_cached */
-#define XCHAL_KIO_CACHED_SIZE          0x10000000      /* size in bytes of kio_cached (assumed power of 2!!!) */
-#define XCHAL_KIO_BYPASS_VADDR         0xF0000000      /* virt.addr of kernel I/O bypass (uncached) static map */
-#define XCHAL_KIO_BYPASS_PADDR         0xF0000000      /* phys.addr of kio_bypass */
-#define XCHAL_KIO_BYPASS_SIZE          0x10000000      /* size in bytes of kio_bypass (assumed power of 2!!!) */
-
-#define XCHAL_SEG_MAPPABLE_VADDR       0x00000000      /* start of largest non-static-mapped virtual addr area */
-#define XCHAL_SEG_MAPPABLE_SIZE                0xD0000000      /* size in bytes of  "  */
-/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size.  */
-#endif
-
-
-/*----------------------------------------------------------------------
-                               MISC
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_NUM_WRITEBUFFER_ENTRIES  4       /* number of write buffer entries */
-
-#define XCHAL_CORE_ID                  "linux_be"      /* configuration's alphanumeric core identifier
-                                                          (CoreID) set in the Xtensa Processor Generator */
-
-#define XCHAL_BUILD_UNIQUE_ID          0x00003256      /* software build-unique ID (22-bit) */
-
-/*  These definitions describe the hardware targeted by this software:  */
-#define XCHAL_HW_CONFIGID0             0xC103D1FF      /* config ID reg 0 value (upper 32 of 64 bits) */
-#define XCHAL_HW_CONFIGID1             0x00803256      /* config ID reg 1 value (lower 32 of 64 bits) */
-#define XCHAL_CONFIGID0                        XCHAL_HW_CONFIGID0      /* for backward compatibility only -- don't use! */
-#define XCHAL_CONFIGID1                        XCHAL_HW_CONFIGID1      /* for backward compatibility only -- don't use! */
-#define XCHAL_HW_RELEASE_MAJOR         1050    /* major release of targeted hardware */
-#define XCHAL_HW_RELEASE_MINOR         1       /* minor release of targeted hardware */
-#define XCHAL_HW_RELEASE_NAME          "T1050.1"       /* full release name of targeted hardware */
-#define XTHAL_HW_REL_T1050     1
-#define XTHAL_HW_REL_T1050_1   1
-#define XCHAL_HW_CONFIGID_RELIABLE     1
-
-
-/*
- *  Miscellaneous special register fields:
- */
-
-
-/*  DBREAKC (special register number 160):  */
-#define XCHAL_DBREAKC_VALIDMASK        0xC000003F      /* bits of DBREAKC that are defined */
-/*  MASK field:  */
-#define XCHAL_DBREAKC_MASK_BITS        6               /* number of bits in MASK field */
-#define XCHAL_DBREAKC_MASK_NUM         64              /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_MASK_SHIFT       0               /* position of MASK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_MASK_MASK        0x0000003F      /* mask of bits in MASK field of DBREAKC */
-/*  LOADBREAK field:  */
-#define XCHAL_DBREAKC_LOADBREAK_BITS   1               /* number of bits in LOADBREAK field */
-#define XCHAL_DBREAKC_LOADBREAK_NUM    2               /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_LOADBREAK_SHIFT  30              /* position of LOADBREAK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_LOADBREAK_MASK   0x40000000      /* mask of bits in LOADBREAK field of DBREAKC */
-/*  STOREBREAK field:  */
-#define XCHAL_DBREAKC_STOREBREAK_BITS  1               /* number of bits in STOREBREAK field */
-#define XCHAL_DBREAKC_STOREBREAK_NUM   2               /* max number of possible causes (2^bits) */
-#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31              /* position of STOREBREAK bits in DBREAKC, starting from lsbit */
-#define XCHAL_DBREAKC_STOREBREAK_MASK  0x80000000      /* mask of bits in STOREBREAK field of DBREAKC */
-
-/*  PS (special register number 230):  */
-#define XCHAL_PS_VALIDMASK     0x00070FFF      /* bits of PS that are defined */
-/*  INTLEVEL field:  */
-#define XCHAL_PS_INTLEVEL_BITS         4               /* number of bits in INTLEVEL field */
-#define XCHAL_PS_INTLEVEL_NUM          16              /* max number of possible causes (2^bits) */
-#define XCHAL_PS_INTLEVEL_SHIFT        0               /* position of INTLEVEL bits in PS, starting from lsbit */
-#define XCHAL_PS_INTLEVEL_MASK         0x0000000F      /* mask of bits in INTLEVEL field of PS */
-/*  EXCM field:  */
-#define XCHAL_PS_EXCM_BITS     1               /* number of bits in EXCM field */
-#define XCHAL_PS_EXCM_NUM      2               /* max number of possible causes (2^bits) */
-#define XCHAL_PS_EXCM_SHIFT    4               /* position of EXCM bits in PS, starting from lsbit */
-#define XCHAL_PS_EXCM_MASK     0x00000010      /* mask of bits in EXCM field of PS */
-/*  PROGSTACK field:  */
-#define XCHAL_PS_PROGSTACK_BITS        1               /* number of bits in PROGSTACK field */
-#define XCHAL_PS_PROGSTACK_NUM         2               /* max number of possible causes (2^bits) */
-#define XCHAL_PS_PROGSTACK_SHIFT       5               /* position of PROGSTACK bits in PS, starting from lsbit */
-#define XCHAL_PS_PROGSTACK_MASK        0x00000020      /* mask of bits in PROGSTACK field of PS */
-/*  RING field:  */
-#define XCHAL_PS_RING_BITS     2               /* number of bits in RING field */
-#define XCHAL_PS_RING_NUM      4               /* max number of possible causes (2^bits) */
-#define XCHAL_PS_RING_SHIFT    6               /* position of RING bits in PS, starting from lsbit */
-#define XCHAL_PS_RING_MASK     0x000000C0      /* mask of bits in RING field of PS */
-/*  OWB field:  */
-#define XCHAL_PS_OWB_BITS      4               /* number of bits in OWB field */
-#define XCHAL_PS_OWB_NUM       16              /* max number of possible causes (2^bits) */
-#define XCHAL_PS_OWB_SHIFT     8               /* position of OWB bits in PS, starting from lsbit */
-#define XCHAL_PS_OWB_MASK      0x00000F00      /* mask of bits in OWB field of PS */
-/*  CALLINC field:  */
-#define XCHAL_PS_CALLINC_BITS  2               /* number of bits in CALLINC field */
-#define XCHAL_PS_CALLINC_NUM   4               /* max number of possible causes (2^bits) */
-#define XCHAL_PS_CALLINC_SHIFT 16              /* position of CALLINC bits in PS, starting from lsbit */
-#define XCHAL_PS_CALLINC_MASK  0x00030000      /* mask of bits in CALLINC field of PS */
-/*  WOE field:  */
-#define XCHAL_PS_WOE_BITS      1               /* number of bits in WOE field */
-#define XCHAL_PS_WOE_NUM       2               /* max number of possible causes (2^bits) */
-#define XCHAL_PS_WOE_SHIFT     18              /* position of WOE bits in PS, starting from lsbit */
-#define XCHAL_PS_WOE_MASK      0x00040000      /* mask of bits in WOE field of PS */
-
-/*  EXCCAUSE (special register number 232):  */
-#define XCHAL_EXCCAUSE_VALIDMASK       0x0000003F      /* bits of EXCCAUSE that are defined */
-/*  EXCCAUSE field:  */
-#define XCHAL_EXCCAUSE_BITS            6               /* number of bits in EXCCAUSE register */
-#define XCHAL_EXCCAUSE_NUM             64              /* max number of possible causes (2^bits) */
-#define XCHAL_EXCCAUSE_SHIFT           0               /* position of EXCCAUSE bits in register, starting from lsbit */
-#define XCHAL_EXCCAUSE_MASK            0x0000003F      /* mask of bits in EXCCAUSE register */
-
-/*  DEBUGCAUSE (special register number 233):  */
-#define XCHAL_DEBUGCAUSE_VALIDMASK     0x0000003F      /* bits of DEBUGCAUSE that are defined */
-/*  ICOUNT field:  */
-#define XCHAL_DEBUGCAUSE_ICOUNT_BITS   1               /* number of bits in ICOUNT field */
-#define XCHAL_DEBUGCAUSE_ICOUNT_NUM    2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT  0               /* position of ICOUNT bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_ICOUNT_MASK   0x00000001      /* mask of bits in ICOUNT field of DEBUGCAUSE */
-/*  IBREAK field:  */
-#define XCHAL_DEBUGCAUSE_IBREAK_BITS   1               /* number of bits in IBREAK field */
-#define XCHAL_DEBUGCAUSE_IBREAK_NUM    2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT  1               /* position of IBREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_IBREAK_MASK   0x00000002      /* mask of bits in IBREAK field of DEBUGCAUSE */
-/*  DBREAK field:  */
-#define XCHAL_DEBUGCAUSE_DBREAK_BITS   1               /* number of bits in DBREAK field */
-#define XCHAL_DEBUGCAUSE_DBREAK_NUM    2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT  2               /* position of DBREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_DBREAK_MASK   0x00000004      /* mask of bits in DBREAK field of DEBUGCAUSE */
-/*  BREAK field:  */
-#define XCHAL_DEBUGCAUSE_BREAK_BITS    1               /* number of bits in BREAK field */
-#define XCHAL_DEBUGCAUSE_BREAK_NUM     2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_BREAK_SHIFT   3               /* position of BREAK bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_BREAK_MASK    0x00000008      /* mask of bits in BREAK field of DEBUGCAUSE */
-/*  BREAKN field:  */
-#define XCHAL_DEBUGCAUSE_BREAKN_BITS   1               /* number of bits in BREAKN field */
-#define XCHAL_DEBUGCAUSE_BREAKN_NUM    2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT  4               /* position of BREAKN bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_BREAKN_MASK   0x00000010      /* mask of bits in BREAKN field of DEBUGCAUSE */
-/*  DEBUGINT field:  */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS         1               /* number of bits in DEBUGINT field */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM          2               /* max number of possible causes (2^bits) */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT        5               /* position of DEBUGINT bits in DEBUGCAUSE, starting from lsbit */
-#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK         0x00000020      /* mask of bits in DEBUGINT field of DEBUGCAUSE */
-
-
-
-/*----------------------------------------------------------------------
-                               ISA
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_HAVE_DENSITY             1       /* 1 if density option configured, 0 otherwise */
-#define XCHAL_HAVE_LOOPS               1       /* 1 if zero-overhead loops option configured, 0 otherwise */
-/*  Misc instructions:  */
-#define XCHAL_HAVE_NSA                 0       /* 1 if NSA/NSAU instructions option configured, 0 otherwise */
-#define XCHAL_HAVE_MINMAX              0       /* 1 if MIN/MAX instructions option configured, 0 otherwise */
-#define XCHAL_HAVE_SEXT                        0       /* 1 if sign-extend instruction option configured, 0 otherwise */
-#define XCHAL_HAVE_CLAMPS              0       /* 1 if CLAMPS instruction option configured, 0 otherwise */
-#define XCHAL_HAVE_MAC16               0       /* 1 if MAC16 option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL16               0       /* 1 if 16-bit integer multiply option configured, 0 otherwise */
-/*#define XCHAL_HAVE_POPC              0*/     /* 1 if CRC instruction option configured, 0 otherwise */
-/*#define XCHAL_HAVE_CRC               0*/     /* 1 if POPC instruction option configured, 0 otherwise */
-
-#define XCHAL_HAVE_SPECULATION         0       /* 1 if speculation option configured, 0 otherwise */
-/*#define XCHAL_HAVE_MP_SYNC           0*/     /* 1 if multiprocessor sync. option configured, 0 otherwise */
-#define XCHAL_HAVE_PRID                        0       /* 1 if processor ID register configured, 0 otherwise */
-
-#define XCHAL_NUM_MISC_REGS            2       /* number of miscellaneous registers (0..4) */
-
-/*  These relate a bit more to TIE:  */
-#define XCHAL_HAVE_BOOLEANS            0       /* 1 if booleans option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32               0       /* 1 if 32-bit integer multiply option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32_HIGH          0       /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
-#define XCHAL_HAVE_FP                  0       /* 1 if floating point option configured, 0 otherwise */
-
-
-/*----------------------------------------------------------------------
-                               DERIVED
-  ----------------------------------------------------------------------*/
-
-#if XCHAL_HAVE_BE
-#define XCHAL_INST_ILLN                        0xD60F          /* 2-byte illegal instruction, msb-first */
-#define XCHAL_INST_ILLN_BYTE0          0xD6            /* 2-byte illegal instruction, 1st byte */
-#define XCHAL_INST_ILLN_BYTE1          0x0F            /* 2-byte illegal instruction, 2nd byte */
-#else
-#define XCHAL_INST_ILLN                        0xF06D          /* 2-byte illegal instruction, lsb-first */
-#define XCHAL_INST_ILLN_BYTE0          0x6D            /* 2-byte illegal instruction, 1st byte */
-#define XCHAL_INST_ILLN_BYTE1          0xF0            /* 2-byte illegal instruction, 2nd byte */
-#endif
-/*  Belongs in xtensa/hal.h:  */
-#define XTHAL_INST_ILL                 0x000000        /* 3-byte illegal instruction */
-
-
-/*
- *  Because information as to exactly which hardware release is targeted
- *  by a given software build is not always available, compile-time HAL
- *  Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE):
- */
-#ifndef XCHAL_HW_RELEASE_MAJOR
-# define XCHAL_HW_CONFIGID_RELIABLE    0
-#endif
-#if XCHAL_HW_CONFIGID_RELIABLE
-# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)     (XTHAL_REL_LE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)     (XTHAL_REL_GE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_AT(major,minor)              (XTHAL_REL_EQ( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
-# define XCHAL_HW_RELEASE_MAJOR_AT(major)              ((XCHAL_HW_RELEASE_MAJOR == (major)) ? 1 : 0)
-#else
-# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)     ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \
-                                                       : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \
-                                                       : XTHAL_MAYBE )
-# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)     ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \
-                                                       : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \
-                                                       : XTHAL_MAYBE )
-# define XCHAL_HW_RELEASE_AT(major,minor)              ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \
-                                                          ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE)
-# define XCHAL_HW_RELEASE_MAJOR_AT(major)              XCHAL_HW_RELEASE_AT(major,0)
-#endif
-
-/*
- *  Specific errata:
- */
-
-/*
- *  Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1;
- *  relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled):
- */
-#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \
-                                        (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \
-                                         || XCHAL_HW_RELEASE_AT(1050,0)))
-
-
-
-#endif /*XTENSA_CONFIG_CORE_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/defs.h b/include/asm-xtensa/xtensa/config-linux_be/defs.h
deleted file mode 100644 (file)
index f7c58b2..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Definitions for Xtensa instructions, types, and protos. */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2.1 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-/* Do not modify. This is automatically generated.*/
-
-#ifndef _XTENSA_BASE_HEADER
-#define _XTENSA_BASE_HEADER
-
-#ifdef __XTENSA__
-#if defined(__GNUC__) && !defined(__XCC__)
-
-#define L8UI_ASM(arr, ars, imm) { \
-  __asm__ volatile("l8ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L8UI(ars, imm) \
-({ \
-  unsigned char _arr; \
-  const unsigned char *_ars = ars; \
-  L8UI_ASM(_arr, _ars, imm); \
-  _arr; \
-})
-
-#define L16UI_ASM(arr, ars, imm) { \
-  __asm__ volatile("l16ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L16UI(ars, imm) \
-({ \
-  unsigned short _arr; \
-  const unsigned short *_ars = ars; \
-  L16UI_ASM(_arr, _ars, imm); \
-  _arr; \
-})
-
-#define L16SI_ASM(arr, ars, imm) {\
-  __asm__ volatile("l16si %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L16SI(ars, imm) \
-({ \
-  signed short _arr; \
-  const signed short *_ars = ars; \
-  L16SI_ASM(_arr, _ars, imm); \
-  _arr; \
-})
-
-#define L32I_ASM(arr, ars, imm) { \
-  __asm__ volatile("l32i %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
-}
-
-#define XT_L32I(ars, imm) \
-({ \
-  unsigned _arr; \
-  const unsigned *_ars = ars; \
-  L32I_ASM(_arr, _ars, imm); \
-  _arr; \
-})
-
-#define S8I_ASM(arr, ars, imm) {\
-  __asm__ volatile("s8i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S8I(arr, ars, imm) \
-({ \
-  signed char _arr = arr; \
-  const signed char *_ars = ars; \
-  S8I_ASM(_arr, _ars, imm); \
-})
-
-#define S16I_ASM(arr, ars, imm) {\
-  __asm__ volatile("s16i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S16I(arr, ars, imm) \
-({ \
-  signed short _arr = arr; \
-  const signed short *_ars = ars; \
-  S16I_ASM(_arr, _ars, imm); \
-})
-
-#define S32I_ASM(arr, ars, imm) { \
-  __asm__ volatile("s32i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
-}
-
-#define XT_S32I(arr, ars, imm) \
-({ \
-  signed int _arr = arr; \
-  const signed int *_ars = ars; \
-  S32I_ASM(_arr, _ars, imm); \
-})
-
-#define ADDI_ASM(art, ars, imm) {\
-   __asm__ ("addi %0, %1, %2" : "=a" (art) : "a" (ars), "i" (imm)); \
-}
-
-#define XT_ADDI(ars, imm) \
-({ \
-   unsigned _art; \
-   unsigned _ars = ars; \
-   ADDI_ASM(_art, _ars, imm); \
-   _art; \
-})
-
-#define ABS_ASM(arr, art) {\
-   __asm__ ("abs %0, %1" : "=a" (arr) : "a" (art)); \
-}
-
-#define XT_ABS(art) \
-({ \
-   unsigned _arr; \
-   signed _art = art; \
-   ABS_ASM(_arr, _art); \
-   _arr; \
-})
-
-/* Note: In the following macros that reference SAR, the magic "state"
-   register is used to capture the dependency on SAR.  This is because
-   SAR is a 5-bit register and thus there are no C types that can be
-   used to represent it.  It doesn't appear that the SAR register is
-   even relevant to GCC, but it is marked as "clobbered" just in
-   case.  */
-
-#define SRC_ASM(arr, ars, art) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("src %0, %1, %2" \
-           : "=a" (arr) : "a" (ars), "a" (art), "t" (_xt_sar)); \
-}
-
-#define XT_SRC(ars, art) \
-({ \
-   unsigned _arr; \
-   unsigned _ars = ars; \
-   unsigned _art = art; \
-   SRC_ASM(_arr, _ars, _art); \
-   _arr; \
-})
-
-#define SSR_ASM(ars) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("ssr %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSR(ars) \
-({ \
-   unsigned _ars = ars; \
-   SSR_ASM(_ars); \
-})
-
-#define SSL_ASM(ars) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("ssl %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSL(ars) \
-({ \
-   unsigned _ars = ars; \
-   SSL_ASM(_ars); \
-})
-
-#define SSA8B_ASM(ars) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("ssa8b %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSA8B(ars) \
-({ \
-   unsigned _ars = ars; \
-   SSA8B_ASM(_ars); \
-})
-
-#define SSA8L_ASM(ars) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("ssa8l %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
-}
-
-#define XT_SSA8L(ars) \
-({ \
-   unsigned _ars = ars; \
-   SSA8L_ASM(_ars); \
-})
-
-#define SSAI_ASM(imm) {\
-   register int _xt_sar __asm__ ("state"); \
-   __asm__ ("ssai %1" : "=t" (_xt_sar) : "i" (imm) : "sar"); \
-}
-
-#define XT_SSAI(imm) \
-({ \
-   SSAI_ASM(imm); \
-})
-
-
-
-
-
-
-
-
-#endif /* __GNUC__ && !__XCC__ */
-
-#ifdef __XCC__
-
-/* Core load/store instructions */
-extern unsigned char _TIE_L8UI(const unsigned char * ars, immediate imm);
-extern unsigned short _TIE_L16UI(const unsigned short * ars, immediate imm);
-extern signed short _TIE_L16SI(const signed short * ars, immediate imm);
-extern unsigned _TIE_L32I(const unsigned * ars, immediate imm);
-extern void _TIE_S8I(unsigned char arr, unsigned char * ars, immediate imm);
-extern void _TIE_S16I(unsigned short arr, unsigned short * ars, immediate imm);
-extern void _TIE_S32I(unsigned arr, unsigned * ars, immediate imm);
-
-#define XT_L8UI  _TIE_L8UI
-#define XT_L16UI _TIE_L16UI
-#define XT_L16SI _TIE_L16SI
-#define XT_L32I  _TIE_L32I
-#define XT_S8I   _TIE_S8I
-#define XT_S16I  _TIE_S16I
-#define XT_S32I  _TIE_S32I
-
-/* Add-immediate instruction */
-extern unsigned _TIE_ADDI(unsigned ars, immediate imm);
-#define XT_ADDI  _TIE_ADDI
-
-/* Absolute value instruction */
-extern unsigned _TIE_ABS(int art);
-#define XT_ABS _TIE_ABS
-
-/* funnel shift instructions */
-extern unsigned _TIE_SRC(unsigned ars, unsigned art);
-#define XT_SRC _TIE_SRC
-extern void _TIE_SSR(unsigned ars);
-#define XT_SSR _TIE_SSR
-extern void _TIE_SSL(unsigned ars);
-#define XT_SSL _TIE_SSL
-extern void _TIE_SSA8B(unsigned ars);
-#define XT_SSA8B _TIE_SSA8B
-extern void _TIE_SSA8L(unsigned ars);
-#define XT_SSA8L _TIE_SSA8L
-extern void _TIE_SSAI(immediate imm);
-#define XT_SSAI _TIE_SSAI
-
-
-#endif /* __XCC__ */
-
-#endif /* __XTENSA__ */
-#endif /* !_XTENSA_BASE_HEADER */
diff --git a/include/asm-xtensa/xtensa/config-linux_be/specreg.h b/include/asm-xtensa/xtensa/config-linux_be/specreg.h
deleted file mode 100644 (file)
index fa4106a..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Xtensa Special Register symbolic names
- */
-
-/* $Id: specreg.h,v 1.2 2003/03/07 19:15:18 joetaylor Exp $ */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2.1 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-#ifndef XTENSA_SPECREG_H
-#define XTENSA_SPECREG_H
-
-/*  Include these special register bitfield definitions, for historical reasons:  */
-#include <xtensa/corebits.h>
-
-
-/*  Special registers:  */
-#define LBEG           0
-#define LEND           1
-#define LCOUNT         2
-#define SAR            3
-#define WINDOWBASE     72
-#define WINDOWSTART    73
-#define PTEVADDR       83
-#define RASID          90
-#define ITLBCFG                91
-#define DTLBCFG                92
-#define IBREAKENABLE   96
-#define DDR            104
-#define IBREAKA_0      128
-#define IBREAKA_1      129
-#define DBREAKA_0      144
-#define DBREAKA_1      145
-#define DBREAKC_0      160
-#define DBREAKC_1      161
-#define EPC_1          177
-#define EPC_2          178
-#define EPC_3          179
-#define EPC_4          180
-#define DEPC           192
-#define EPS_2          194
-#define EPS_3          195
-#define EPS_4          196
-#define EXCSAVE_1      209
-#define EXCSAVE_2      210
-#define EXCSAVE_3      211
-#define EXCSAVE_4      212
-#define INTERRUPT      226
-#define INTENABLE      228
-#define PS             230
-#define EXCCAUSE       232
-#define DEBUGCAUSE     233
-#define CCOUNT         234
-#define ICOUNT         236
-#define ICOUNTLEVEL    237
-#define EXCVADDR       238
-#define CCOMPARE_0     240
-#define CCOMPARE_1     241
-#define CCOMPARE_2     242
-#define MISC_REG_0     244
-#define MISC_REG_1     245
-
-/*  Special cases (bases of special register series):  */
-#define IBREAKA                128
-#define DBREAKA                144
-#define DBREAKC                160
-#define EPC            176
-#define EPS            192
-#define EXCSAVE                208
-#define CCOMPARE       240
-
-/*  Special names for read-only and write-only interrupt registers:  */
-#define INTREAD                226
-#define INTSET         226
-#define INTCLEAR       227
-
-#endif /* XTENSA_SPECREG_H */
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/system.h b/include/asm-xtensa/xtensa/config-linux_be/system.h
deleted file mode 100644 (file)
index cf9d4d3..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration
- *
- *  NOTE: The location and contents of this file are highly subject to change.
- *
- *  Source for configuration-independent binaries (which link in a
- *  configuration-specific HAL library) must NEVER include this file.
- *  The HAL itself has historically included this file in some instances,
- *  but this is not appropriate either, because the HAL is meant to be
- *  core-specific but system independent.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2.1 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_SYSTEM_H
-#define XTENSA_CONFIG_SYSTEM_H
-
-/*#include <xtensa/hal.h>*/
-
-
-
-/*----------------------------------------------------------------------
-                               DEVICE ADDRESSES
-  ----------------------------------------------------------------------*/
-
-/*
- *  Strange place to find these, but the configuration GUI
- *  allows moving these around to account for various core
- *  configurations.  Specific boards (and their BSP software)
- *  will have specific meanings for these components.
- */
-
-/*  I/O Block areas:  */
-#define XSHAL_IOBLOCK_CACHED_VADDR     0xE0000000
-#define XSHAL_IOBLOCK_CACHED_PADDR     0xF0000000
-#define XSHAL_IOBLOCK_CACHED_SIZE      0x0E000000
-
-#define XSHAL_IOBLOCK_BYPASS_VADDR     0xF0000000
-#define XSHAL_IOBLOCK_BYPASS_PADDR     0xF0000000
-#define XSHAL_IOBLOCK_BYPASS_SIZE      0x0E000000
-
-/*  System ROM:  */
-#define XSHAL_ROM_VADDR                0xEE000000
-#define XSHAL_ROM_PADDR                0xFE000000
-#define XSHAL_ROM_SIZE         0x00400000
-/*  Largest available area (free of vectors):  */
-#define XSHAL_ROM_AVAIL_VADDR  0xEE00052C
-#define XSHAL_ROM_AVAIL_VSIZE  0x003FFAD4
-
-/*  System RAM:  */
-#define XSHAL_RAM_VADDR                0xD0000000
-#define XSHAL_RAM_PADDR                0x00000000
-#define XSHAL_RAM_VSIZE                0x08000000
-#define XSHAL_RAM_PSIZE                0x10000000
-#define XSHAL_RAM_SIZE         XSHAL_RAM_PSIZE
-/*  Largest available area (free of vectors):  */
-#define XSHAL_RAM_AVAIL_VADDR  0xD0000370
-#define XSHAL_RAM_AVAIL_VSIZE  0x07FFFC90
-
-/*
- *  Shadow system RAM (same device as system RAM, at different address).
- *  (Emulation boards need this for the SONIC Ethernet driver
- *   when data caches are configured for writeback mode.)
- *  NOTE: on full MMU configs, this points to the BYPASS virtual address
- *  of system RAM, ie. is the same as XSHAL_RAM_* except that virtual
- *  addresses are viewed through the BYPASS static map rather than
- *  the CACHED static map.
- */
-#define XSHAL_RAM_BYPASS_VADDR         0xD8000000
-#define XSHAL_RAM_BYPASS_PADDR         0x00000000
-#define XSHAL_RAM_BYPASS_PSIZE         0x08000000
-
-/*  Alternate system RAM (different device than system RAM):  */
-#define XSHAL_ALTRAM_VADDR             0xCEE00000
-#define XSHAL_ALTRAM_PADDR             0xC0000000
-#define XSHAL_ALTRAM_SIZE              0x00200000
-
-
-/*----------------------------------------------------------------------
- *                     DEVICE-ADDRESS DEPENDENT...
- *
- *  Values written to CACHEATTR special register (or its equivalent)
- *  to enable and disable caches in various modes.
- *----------------------------------------------------------------------*/
-
-/*----------------------------------------------------------------------
-                       BACKWARD COMPATIBILITY ...
-  ----------------------------------------------------------------------*/
-
-/*
- *  NOTE:  the following two macros are DEPRECATED.  Use the latter
- *  board-specific macros instead, which are specially tuned for the
- *  particular target environments' memory maps.
- */
-#define XSHAL_CACHEATTR_BYPASS         XSHAL_XT2000_CACHEATTR_BYPASS   /* disable caches in bypass mode */
-#define XSHAL_CACHEATTR_DEFAULT                XSHAL_XT2000_CACHEATTR_DEFAULT  /* default setting to enable caches (no writeback!) */
-
-/*----------------------------------------------------------------------
-                       ISS (Instruction Set Simulator) SPECIFIC ...
-  ----------------------------------------------------------------------*/
-
-#define XSHAL_ISS_CACHEATTR_WRITEBACK  0x1122222F      /* enable caches in write-back mode */
-#define XSHAL_ISS_CACHEATTR_WRITEALLOC 0x1122222F      /* enable caches in write-allocate mode */
-#define XSHAL_ISS_CACHEATTR_WRITETHRU  0x1122222F      /* enable caches in write-through mode */
-#define XSHAL_ISS_CACHEATTR_BYPASS     0x2222222F      /* disable caches in bypass mode */
-#define XSHAL_ISS_CACHEATTR_DEFAULT    XSHAL_ISS_CACHEATTR_WRITEBACK   /* default setting to enable caches */
-
-/*  For Coware only:  */
-#define XSHAL_COWARE_CACHEATTR_WRITEBACK       0x11222222      /* enable caches in write-back mode */
-#define XSHAL_COWARE_CACHEATTR_WRITEALLOC      0x11222222      /* enable caches in write-allocate mode */
-#define XSHAL_COWARE_CACHEATTR_WRITETHRU       0x11222222      /* enable caches in write-through mode */
-#define XSHAL_COWARE_CACHEATTR_BYPASS          0x22222222      /* disable caches in bypass mode */
-#define XSHAL_COWARE_CACHEATTR_DEFAULT         XSHAL_COWARE_CACHEATTR_WRITEBACK        /* default setting to enable caches */
-
-/*  For BFM and other purposes:  */
-#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK     0x11222222      /* enable caches without any invalid regions */
-#define XSHAL_ALLVALID_CACHEATTR_DEFAULT       XSHAL_ALLVALID_CACHEATTR_WRITEBACK      /* default setting for caches without any invalid regions */
-
-#define XSHAL_ISS_PIPE_REGIONS 0
-#define XSHAL_ISS_SDRAM_REGIONS        0
-
-
-/*----------------------------------------------------------------------
-                       XT2000 BOARD SPECIFIC ...
-  ----------------------------------------------------------------------*/
-
-#define XSHAL_XT2000_CACHEATTR_WRITEBACK       0x22FFFFFF      /* enable caches in write-back mode */
-#define XSHAL_XT2000_CACHEATTR_WRITEALLOC      0x22FFFFFF      /* enable caches in write-allocate mode */
-#define XSHAL_XT2000_CACHEATTR_WRITETHRU       0x22FFFFFF      /* enable caches in write-through mode */
-#define XSHAL_XT2000_CACHEATTR_BYPASS          0x22FFFFFF      /* disable caches in bypass mode */
-#define XSHAL_XT2000_CACHEATTR_DEFAULT         XSHAL_XT2000_CACHEATTR_WRITEBACK        /* default setting to enable caches */
-
-#define XSHAL_XT2000_PIPE_REGIONS      0x00001000      /* BusInt pipeline regions */
-#define XSHAL_XT2000_SDRAM_REGIONS     0x00000005      /* BusInt SDRAM regions */
-
-
-/*----------------------------------------------------------------------
-                               VECTOR SIZES
-  ----------------------------------------------------------------------*/
-
-/*
- *  Sizes allocated to vectors by the system (memory map) configuration.
- *  These sizes are constrained by core configuration (eg. one vector's
- *  code cannot overflow into another vector) but are dependent on the
- *  system or board (or LSP) memory map configuration.
- *
- *  Whether or not each vector happens to be in a system ROM is also
- *  a system configuration matter, sometimes useful, included here also:
- */
-#define XSHAL_RESET_VECTOR_SIZE        0x000004E0
-#define XSHAL_RESET_VECTOR_ISROM       1
-#define XSHAL_USER_VECTOR_SIZE 0x0000001C
-#define XSHAL_USER_VECTOR_ISROM        0
-#define XSHAL_PROGRAMEXC_VECTOR_SIZE   XSHAL_USER_VECTOR_SIZE  /* for backward compatibility */
-#define XSHAL_USEREXC_VECTOR_SIZE      XSHAL_USER_VECTOR_SIZE  /* for backward compatibility */
-#define XSHAL_KERNEL_VECTOR_SIZE       0x0000001C
-#define XSHAL_KERNEL_VECTOR_ISROM      0
-#define XSHAL_STACKEDEXC_VECTOR_SIZE   XSHAL_KERNEL_VECTOR_SIZE        /* for backward compatibility */
-#define XSHAL_KERNELEXC_VECTOR_SIZE    XSHAL_KERNEL_VECTOR_SIZE        /* for backward compatibility */
-#define XSHAL_DOUBLEEXC_VECTOR_SIZE    0x000000E0
-#define XSHAL_DOUBLEEXC_VECTOR_ISROM   0
-#define XSHAL_WINDOW_VECTORS_SIZE      0x00000180
-#define XSHAL_WINDOW_VECTORS_ISROM     0
-#define XSHAL_INTLEVEL2_VECTOR_SIZE    0x0000000C
-#define XSHAL_INTLEVEL2_VECTOR_ISROM   0
-#define XSHAL_INTLEVEL3_VECTOR_SIZE    0x0000000C
-#define XSHAL_INTLEVEL3_VECTOR_ISROM   0
-#define XSHAL_INTLEVEL4_VECTOR_SIZE    0x0000000C
-#define XSHAL_INTLEVEL4_VECTOR_ISROM   1
-#define XSHAL_DEBUG_VECTOR_SIZE                XSHAL_INTLEVEL4_VECTOR_SIZE
-#define XSHAL_DEBUG_VECTOR_ISROM       XSHAL_INTLEVEL4_VECTOR_ISROM
-
-
-#endif /*XTENSA_CONFIG_SYSTEM_H*/
-
diff --git a/include/asm-xtensa/xtensa/config-linux_be/tie.h b/include/asm-xtensa/xtensa/config-linux_be/tie.h
deleted file mode 100644 (file)
index 3c2e514..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * xtensa/config/tie.h -- HAL definitions that are dependent on CORE and TIE configuration
- *
- *  This header file is sometimes referred to as the "compile-time HAL" or CHAL.
- *  It was generated for a specific Xtensa processor configuration,
- *  and furthermore for a specific set of TIE source files that extend
- *  basic core functionality.
- *
- *  Source for configuration-independent binaries (which link in a
- *  configuration-specific HAL library) must NEVER include this file.
- *  It is perfectly normal, however, for the HAL source itself to include this file.
- */
-
-/*
- * Copyright (c) 2003 Tensilica, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2.1 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
- * USA.
- */
-
-
-#ifndef XTENSA_CONFIG_TIE_H
-#define XTENSA_CONFIG_TIE_H
-
-#include <xtensa/hal.h>
-
-
-/*----------------------------------------------------------------------
-                               GENERAL
-  ----------------------------------------------------------------------*/
-
-/*
- *  Separators for macros that expand into arrays.
- *  These can be predefined by files that #include this one,
- *  when different separators are required.
- */
-/*  Element separator for macros that expand into 1-dimensional arrays:  */
-#ifndef XCHAL_SEP
-#define XCHAL_SEP                      ,
-#endif
-/*  Array separator for macros that expand into 2-dimensional arrays:  */
-#ifndef XCHAL_SEP2
-#define XCHAL_SEP2                     },{
-#endif
-
-
-
-
-
-
-/*----------------------------------------------------------------------
-                       COPROCESSORS and EXTRA STATE
-  ----------------------------------------------------------------------*/
-
-#define XCHAL_CP_NUM                   0       /* number of coprocessors */
-#define XCHAL_CP_MAX                   0       /* max coprocessor id plus one (0 if none) */
-#define XCHAL_CP_MASK                  0x00    /* bitmask of coprocessors by id */
-
-/*  Space for coprocessors' state save areas:  */
-#define XCHAL_CP0_SA_SIZE              0
-#define XCHAL_CP1_SA_SIZE              0
-#define XCHAL_CP2_SA_SIZE              0
-#define XCHAL_CP3_SA_SIZE              0
-#define XCHAL_CP4_SA_SIZE              0
-#define XCHAL_CP5_SA_SIZE              0
-#define XCHAL_CP6_SA_SIZE              0
-#define XCHAL_CP7_SA_SIZE              0
-/*  Minimum required alignments of CP state save areas:  */
-#define XCHAL_CP0_SA_ALIGN             1
-#define XCHAL_CP1_SA_ALIGN             1
-#define XCHAL_CP2_SA_ALIGN             1
-#define XCHAL_CP3_SA_ALIGN             1
-#define XCHAL_CP4_SA_ALIGN             1
-#define XCHAL_CP5_SA_ALIGN             1
-#define XCHAL_CP6_SA_ALIGN             1
-#define XCHAL_CP7_SA_ALIGN             1
-
-/*  Indexing macros:  */
-#define _XCHAL_CP_SA_SIZE(n)           XCHAL_CP ## n ## _SA_SIZE
-#define XCHAL_CP_SA_SIZE(n)            _XCHAL_CP_SA_SIZE(n)    /* n = 0 .. 7 */
-#define _XCHAL_CP_SA_ALIGN(n)          XCHAL_CP ## n ## _SA_ALIGN
-#define XCHAL_CP_SA_ALIGN(n)           _XCHAL_CP_SA_ALIGN(n)   /* n = 0 .. 7 */
-
-
-/*  Space for "extra" state (user special registers and non-cp TIE) save area:  */
-#define XCHAL_EXTRA_SA_SIZE            0
-#define XCHAL_EXTRA_SA_ALIGN           1
-
-/*  Total save area size (extra + all coprocessors)  */
-/*  (not useful until xthal_{save,restore}_all_extra() is implemented,  */
-/*   but included for Tor2 beta; doesn't account for alignment!):  */
-#define XCHAL_CPEXTRA_SA_SIZE_TOR2     0       /* Tor2Beta temporary definition -- do not use */
-
-/*  Combined required alignment for all CP and EXTRA state save areas  */
-/*  (does not include required alignment for any base config registers):  */
-#define XCHAL_CPEXTRA_SA_ALIGN         1
-
-/* ... */
-
-
-#ifdef _ASMLANGUAGE
-/*
- *  Assembly-language specific definitions (assembly macros, etc.).
- */
-#include <xtensa/config/specreg.h>
-
-/********************
- *  Macros to save and restore the non-coprocessor TIE portion of EXTRA state.
- */
-
-/* (none) */
-
-
-/********************
- *  Macros to create functions that save and restore all EXTRA (non-coprocessor) state
- *  (does not include zero-overhead loop registers and non-optional registers).
- */
-
-       /*
-        *  Macro that expands to the body of a function that
-        *  stores the extra (non-coprocessor) optional/custom state.
-        *      Entry:  a2 = ptr to save area in which to save extra state
-        *      Exit:   any register a2-a15 (?) may have been clobbered.
-        */
-       .macro  xchal_extra_store_funcbody
-       .endm
-
-
-       /*
-        *  Macro that expands to the body of a function that
-        *  loads the extra (non-coprocessor) optional/custom state.
-        *      Entry:  a2 = ptr to save area from which to restore extra state
-        *      Exit:   any register a2-a15 (?) may have been clobbered.
-        */
-       .macro  xchal_extra_load_funcbody
-       .endm
-
-
-/********************
- *  Macros to save and restore the state of each TIE coprocessor.
- */
-
-
-
-/********************
- *  Macros to create functions that save and restore the state of *any* TIE coprocessor.
- */
-
-       /*
-        *  Macro that expands to the body of a function
-        *  that stores the selected coprocessor's state (registers etc).
-        *      Entry:  a2 = ptr to save area in which to save cp state
-        *              a3 = coprocessor number
-        *      Exit:   any register a2-a15 (?) may have been clobbered.
-        */
-       .macro  xchal_cpi_store_funcbody
-       .endm
-
-
-       /*
-        *  Macro that expands to the body of a function
-        *  that loads the selected coprocessor's state (registers etc).
-        *      Entry:  a2 = ptr to save area from which to restore cp state
-        *              a3 = coprocessor number
-        *      Exit:   any register a2-a15 (?) may have been clobbered.
-        */
-       .macro  xchal_cpi_load_funcbody
-       .endm
-
-#endif /*_ASMLANGUAGE*/
-
-
-/*
- *  Contents of save areas in terms of libdb register numbers.
- *  NOTE:  CONTENTS_LIBDB_{UREG,REGF} macros are not defined in this file;
- *  it is up to the user of this header file to define these macros
- *  usefully before each expansion of the CONTENTS_LIBDB macros.
- *  (Fields rsv[123] are reserved for future additions; they are currently
- *   set to zero but may be set to some useful values in the future.)
- *
- *     CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, bitmask, rsv2, rsv3)
- *     CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, bitmask, rsv2, rsv3)
- *     CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, numentries, contentsize, regname_base, regfile_name, rsv2, rsv3)
- */
-
-#define XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM      0
-#define XCHAL_EXTRA_SA_CONTENTS_LIBDB  /* empty */
-
-#define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP0_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP1_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP2_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP3_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP4_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP5_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP6_SA_CONTENTS_LIBDB    /* empty */
-
-#define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM        0
-#define XCHAL_CP7_SA_CONTENTS_LIBDB    /* empty */
-
-
-
-
-
-
-/*----------------------------------------------------------------------
-                               MISC
-  ----------------------------------------------------------------------*/
-
-#if 0  /* is there something equivalent for user TIE? */
-#define XCHAL_CORE_ID                  "linux_be"      /* configuration's alphanumeric core identifier
-                                                          (CoreID) set in the Xtensa Processor Generator */
-
-#define XCHAL_BUILD_UNIQUE_ID          0x00003256      /* software build-unique ID (22-bit) */
-
-/*  These definitions describe the hardware targeted by this software:  */
-#define XCHAL_HW_CONFIGID0             0xC103D1FF      /* config ID reg 0 value (upper 32 of 64 bits) */
-#define XCHAL_HW_CONFIGID1             0x00803256      /* config ID reg 1 value (lower 32 of 64 bits) */
-#define XCHAL_CONFIGID0                        XCHAL_HW_CONFIGID0      /* for backward compatibility only -- don't use! */
-#define XCHAL_CONFIGID1                        XCHAL_HW_CONFIGID1      /* for backward compatibility only -- don't use! */
-#define XCHAL_HW_RELEASE_MAJOR         1050    /* major release of targeted hardware */
-#define XCHAL_HW_RELEASE_MINOR         1       /* minor release of targeted hardware */
-#define XCHAL_HW_RELEASE_NAME          "T1050.1"       /* full release name of targeted hardware */
-#define XTHAL_HW_REL_T1050     1
-#define XTHAL_HW_REL_T1050_1   1
-#define XCHAL_HW_CONFIGID_RELIABLE     1
-#endif /*0*/
-
-
-
-/*----------------------------------------------------------------------
-                               ISA
-  ----------------------------------------------------------------------*/
-
-#if 0  /* these probably don't belong here, but are related to or implemented using TIE */
-#define XCHAL_HAVE_BOOLEANS            0       /* 1 if booleans option configured, 0 otherwise */
-/*  Misc instructions:  */
-#define XCHAL_HAVE_MUL32               0       /* 1 if 32-bit integer multiply option configured, 0 otherwise */
-#define XCHAL_HAVE_MUL32_HIGH          0       /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
-
-#define XCHAL_HAVE_FP                  0       /* 1 if floating point option configured, 0 otherwise */
-#endif /*0*/
-
-
-#endif /*XTENSA_CONFIG_TIE_H*/
-
diff --git a/include/asm-xtensa/xtensa/coreasm.h b/include/asm-xtensa/xtensa/coreasm.h
deleted file mode 100644 (file)
index a8cfb54..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-#ifndef XTENSA_COREASM_H
-#define XTENSA_COREASM_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/coreasm.h -- assembler-specific
- * definitions that depend on CORE configuration.
- *
- * Source for configuration-independent binaries (which link in a
- * configuration-specific HAL library) must NEVER include this file.
- * It is perfectly normal, however, for the HAL itself to include this
- * file.
- *
- * This file must NOT include xtensa/config/system.h.  Any assembler
- * header file that depends on system information should likely go in
- * a new systemasm.h (or sysasm.h) header file.
- *
- *  NOTE: macro beqi32 is NOT configuration-dependent, and is placed
- *        here til we will have configuration-independent header file.
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/specreg.h>
-
-/*
- *  Assembly-language specific definitions (assembly macros, etc.).
- */
-
-/*----------------------------------------------------------------------
- *  find_ms_setbit
- *
- *  This macro finds the most significant bit that is set in <as>
- *  and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.
- *  The index counts starting at zero for the lsbit, so the return
- *  value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).
- *
- *  Parameters:
- *     <ad>    destination address register (any register)
- *     <as>    source address register
- *     <at>    temporary address register (must be different than <as>)
- *     <base>  constant value added to result (usually 0 or 1)
- *  On entry:
- *     <ad> = undefined if different than <as>
- *     <as> = value whose most significant set bit is to be found
- *     <at> = undefined
- *     no other registers are used by this macro.
- *  On exit:
- *     <ad> = <base> + index of msbit set in original <as>,
- *          = <base> - 1 if original <as> was zero.
- *     <as> clobbered (if not <ad>)
- *     <at> clobbered (if not <ad>)
- *  Example:
- *     find_ms_setbit a0, a4, a0, 0            -- return in a0 index of msbit set in a4
- */
-
-       .macro  find_ms_setbit ad, as, at, base
-#if XCHAL_HAVE_NSA
-       movi    \at, 31+\base
-       nsau    \as, \as        // get index of \as, numbered from msbit (32 if absent)
-       sub     \ad, \at, \as   // get numbering from lsbit (0..31, -1 if absent)
-#else /* XCHAL_HAVE_NSA */
-       movi    \at, \base      // start with result of 0 (point to lsbit of 32)
-
-       beqz    \as, 2f         // special case for zero argument: return -1
-       bltui   \as, 0x10000, 1f        // is it one of the 16 lsbits? (if so, check lower 16 bits)
-       addi    \at, \at, 16    // no, increment result to upper 16 bits (of 32)
-       //srli  \as, \as, 16    // check upper half (shift right 16 bits)
-       extui   \as, \as, 16, 16        // check upper half (shift right 16 bits)
-1:     bltui   \as, 0x100, 1f  // is it one of the 8 lsbits? (if so, check lower 8 bits)
-       addi    \at, \at, 8     // no, increment result to upper 8 bits (of 16)
-       srli    \as, \as, 8     // shift right to check upper 8 bits
-1:     bltui   \as, 0x10, 1f   // is it one of the 4 lsbits? (if so, check lower 4 bits)
-       addi    \at, \at, 4     // no, increment result to upper 4 bits (of 8)
-       srli    \as, \as, 4     // shift right 4 bits to check upper half
-1:     bltui   \as, 0x4, 1f    // is it one of the 2 lsbits? (if so, check lower 2 bits)
-       addi    \at, \at, 2     // no, increment result to upper 2 bits (of 4)
-       srli    \as, \as, 2     // shift right 2 bits to check upper half
-1:     bltui   \as, 0x2, 1f    // is it the lsbit?
-       addi    \at, \at, 2     // no, increment result to upper bit (of 2)
-2:     addi    \at, \at, -1    // (from just above: add 1;  from beqz: return -1)
-       //srli  \as, \as, 1
-1:                             // done! \at contains index of msbit set (or -1 if none set)
-       .if     0x\ad - 0x\at   // destination different than \at ? (works because regs are a0-a15)
-       mov     \ad, \at        // then move result to \ad
-       .endif
-#endif /* XCHAL_HAVE_NSA */
-       .endm   // find_ms_setbit
-
-/*----------------------------------------------------------------------
- *  find_ls_setbit
- *
- *  This macro finds the least significant bit that is set in <as>,
- *  and return its index in <ad>.
- *  Usage is the same as for the find_ms_setbit macro.
- *  Example:
- *     find_ls_setbit a0, a4, a0, 0    -- return in a0 index of lsbit set in a4
- */
-
-       .macro  find_ls_setbit ad, as, at, base
-       neg     \at, \as        // keep only the least-significant bit that is set...
-       and     \as, \at, \as   // ... in \as
-       find_ms_setbit  \ad, \as, \at, \base
-       .endm   // find_ls_setbit
-
-/*----------------------------------------------------------------------
- *  find_ls_one
- *
- *  Same as find_ls_setbit with base zero.
- *  Source (as) and destination (ad) registers must be different.
- *  Provided for backward compatibility.
- */
-
-       .macro  find_ls_one ad, as
-       find_ls_setbit  \ad, \as, \ad, 0
-       .endm   // find_ls_one
-
-/*----------------------------------------------------------------------
- *  floop, floopnez, floopgtz, floopend
- *
- *  These macros are used for fast inner loops that
- *  work whether or not the Loops options is configured.
- *  If the Loops option is configured, they simply use
- *  the zero-overhead LOOP instructions; otherwise
- *  they use explicit decrement and branch instructions.
- *
- *  They are used in pairs, with floop, floopnez or floopgtz
- *  at the beginning of the loop, and floopend at the end.
- *
- *  Each pair of loop macro calls must be given the loop count
- *  address register and a unique label for that loop.
- *
- *  Example:
- *
- *     movi     a3, 16     // loop 16 times
- *     floop    a3, myloop1
- *     :
- *     bnez     a7, end1       // exit loop if a7 != 0
- *     :
- *     floopend a3, myloop1
- *  end1:
- *
- *  Like the LOOP instructions, these macros cannot be
- *  nested, must include at least one instruction,
- *  cannot call functions inside the loop, etc.
- *  The loop can be exited by jumping to the instruction
- *  following floopend (or elsewhere outside the loop),
- *  or continued by jumping to a NOP instruction placed
- *  immediately before floopend.
- *
- *  Unlike LOOP instructions, the register passed to floop*
- *  cannot be used inside the loop, because it is used as
- *  the loop counter if the Loops option is not configured.
- *  And its value is undefined after exiting the loop.
- *  And because the loop counter register is active inside
- *  the loop, you can't easily use this construct to loop
- *  across a register file using ROTW as you might with LOOP
- *  instructions, unless you copy the loop register along.
- */
-
-       /*  Named label version of the macros:  */
-
-       .macro  floop           ar, endlabel
-       floop_          \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
-       .endm
-
-       .macro  floopnez        ar, endlabel
-       floopnez_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
-       .endm
-
-       .macro  floopgtz        ar, endlabel
-       floopgtz_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
-       .endm
-
-       .macro  floopend        ar, endlabel
-       floopend_       \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
-       .endm
-
-       /*  Numbered local label version of the macros:  */
-#if 0 /*UNTESTED*/
-       .macro  floop89         ar
-       floop_          \ar, 8, 9f
-       .endm
-
-       .macro  floopnez89      ar
-       floopnez_       \ar, 8, 9f
-       .endm
-
-       .macro  floopgtz89      ar
-       floopgtz_       \ar, 8, 9f
-       .endm
-
-       .macro  floopend89      ar
-       floopend_       \ar, 8b, 9
-       .endm
-#endif /*0*/
-
-       /*  Underlying version of the macros:  */
-
-       .macro  floop_  ar, startlabel, endlabelref
-       .ifdef  _infloop_
-       .if     _infloop_
-       .err    // Error: floop cannot be nested
-       .endif
-       .endif
-       .set    _infloop_, 1
-#if XCHAL_HAVE_LOOPS
-       loop    \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
-\startlabel:
-       addi    \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
-       .endm   // floop_
-
-       .macro  floopnez_       ar, startlabel, endlabelref
-       .ifdef  _infloop_
-       .if     _infloop_
-       .err    // Error: floopnez cannot be nested
-       .endif
-       .endif
-       .set    _infloop_, 1
-#if XCHAL_HAVE_LOOPS
-       loopnez \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
-       beqz    \ar, \endlabelref
-\startlabel:
-       addi    \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
-       .endm   // floopnez_
-
-       .macro  floopgtz_       ar, startlabel, endlabelref
-       .ifdef  _infloop_
-       .if     _infloop_
-       .err    // Error: floopgtz cannot be nested
-       .endif
-       .endif
-       .set    _infloop_, 1
-#if XCHAL_HAVE_LOOPS
-       loopgtz \ar, \endlabelref
-#else /* XCHAL_HAVE_LOOPS */
-       bltz    \ar, \endlabelref
-       beqz    \ar, \endlabelref
-\startlabel:
-       addi    \ar, \ar, -1
-#endif /* XCHAL_HAVE_LOOPS */
-       .endm   // floopgtz_
-
-
-       .macro  floopend_       ar, startlabelref, endlabel
-       .ifndef _infloop_
-       .err    // Error: floopend without matching floopXXX
-       .endif
-       .ifeq   _infloop_
-       .err    // Error: floopend without matching floopXXX
-       .endif
-       .set    _infloop_, 0
-#if ! XCHAL_HAVE_LOOPS
-       bnez    \ar, \startlabelref
-#endif /* XCHAL_HAVE_LOOPS */
-\endlabel:
-       .endm   // floopend_
-
-/*----------------------------------------------------------------------
- *  crsil  --  conditional RSIL (read/set interrupt level)
- *
- *  Executes the RSIL instruction if it exists, else just reads PS.
- *  The RSIL instruction does not exist in the new exception architecture
- *  if the interrupt option is not selected.
- */
-
-       .macro  crsil   ar, newlevel
-#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS
-       rsil    \ar, \newlevel
-#else
-       rsr     \ar, PS
-#endif
-       .endm   // crsil
-
-/*----------------------------------------------------------------------
- *  window_spill{4,8,12}
- *
- *  These macros spill callers' register windows to the stack.
- *  They work for both privileged and non-privileged tasks.
- *  Must be called from a windowed ABI context, eg. within
- *  a windowed ABI function (ie. valid stack frame, window
- *  exceptions enabled, not in exception mode, etc).
- *
- *  This macro requires a single invocation of the window_spill_common
- *  macro in the same assembly unit and section.
- *
- *  Note that using window_spill{4,8,12} macros is more efficient
- *  than calling a function implemented using window_spill_function,
- *  because the latter needs extra code to figure out the size of
- *  the call to the spilling function.
- *
- *  Example usage:
- *
- *             .text
- *             .align  4
- *             .global some_function
- *             .type   some_function,@function
- *     some_function:
- *             entry   a1, 16
- *             :
- *             :
- *
- *             window_spill4   // spill windows of some_function's callers; preserves a0..a3 only;
- *                             // to use window_spill{8,12} in this example function we'd have
- *                             // to increase space allocated by the entry instruction, because
- *                             // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed
- *                             // for call8/window_spill8 or call12/window_spill12 respectively.
- *             :
- *
- *             retw
- *
- *             window_spill_common     // instantiates code used by window_spill4
- *
- *
- *  On entry:
- *     none (if window_spill4)
- *     stack frame has enough space allocated for call8 (if window_spill8)
- *     stack frame has enough space allocated for call12 (if window_spill12)
- *  On exit:
- *      a4..a15 clobbered (if window_spill4)
- *      a8..a15 clobbered (if window_spill8)
- *     a12..a15 clobbered (if window_spill12)
- *     no caller windows are in live registers
- */
-
-       .macro  window_spill4
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
-       movi    a15, 0                  // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
-       call4   .L__wdwspill_assist28   // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
-       call4   .L__wdwspill_assist60   // call deep enough to clear out any live callers
-# endif
-#endif
-       .endm   // window_spill4
-
-       .macro  window_spill8
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
-       movi    a15, 0                  // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
-       call8   .L__wdwspill_assist24   // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
-       call8   .L__wdwspill_assist56   // call deep enough to clear out any live callers
-# endif
-#endif
-       .endm   // window_spill8
-
-       .macro  window_spill12
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 16
-       movi    a15, 0                  // for 16-register files, no need to call to reach the end
-# elif XCHAL_NUM_AREGS == 32
-       call12  .L__wdwspill_assist20   // call deep enough to clear out any live callers
-# elif XCHAL_NUM_AREGS == 64
-       call12  .L__wdwspill_assist52   // call deep enough to clear out any live callers
-# endif
-#endif
-       .endm   // window_spill12
-
-/*----------------------------------------------------------------------
- *  window_spill_function
- *
- *  This macro outputs a function that will spill its caller's callers'
- *  register windows to the stack.  Eg. it could be used to implement
- *  a version of xthal_window_spill() that works in non-privileged tasks.
- *  This works for both privileged and non-privileged tasks.
- *
- *  Typical usage:
- *
- *             .text
- *             .align  4
- *             .global my_spill_function
- *             .type   my_spill_function,@function
- *     my_spill_function:
- *             window_spill_function
- *
- *  On entry to resulting function:
- *     none
- *  On exit from resulting function:
- *     none (no caller windows are in live registers)
- */
-
-       .macro  window_spill_function
-#if XCHAL_HAVE_WINDOWED
-# if XCHAL_NUM_AREGS == 32
-       entry   sp, 48
-       bbci.l  a0, 31, 1f              // branch if called with call4
-       bbsi.l  a0, 30, 2f              // branch if called with call12
-       call8   .L__wdwspill_assist16   // called with call8, only need another 8
-       retw
-1:     call12  .L__wdwspill_assist16   // called with call4, only need another 12
-       retw
-2:     call4   .L__wdwspill_assist16   // called with call12, only need another 4
-       retw
-# elif XCHAL_NUM_AREGS == 64
-       entry   sp, 48
-       bbci.l  a0, 31, 1f              // branch if called with call4
-       bbsi.l  a0, 30, 2f              // branch if called with call12
-       call4   .L__wdwspill_assist52   // called with call8, only need a call4
-       retw
-1:     call8   .L__wdwspill_assist52   // called with call4, only need a call8
-       retw
-2:     call12  .L__wdwspill_assist40   // called with call12, can skip a call12
-       retw
-# elif XCHAL_NUM_AREGS == 16
-       entry   sp, 16
-       bbci.l  a0, 31, 1f      // branch if called with call4
-       bbsi.l  a0, 30, 2f      // branch if called with call12
-       movi    a7, 0           // called with call8
-       retw
-1:     movi    a11, 0          // called with call4
-2:     retw                    // if called with call12, everything already spilled
-
-//     movi    a15, 0          // trick to spill all but the direct caller
-//     j       1f
-//     //  The entry instruction is magical in the assembler (gets auto-aligned)
-//     //  so we have to jump to it to avoid falling through the padding.
-//     //  We need entry/retw to know where to return.
-//1:   entry   sp, 16
-//     retw
-# else
-#  error "unrecognized address register file size"
-# endif
-#endif /* XCHAL_HAVE_WINDOWED */
-       window_spill_common
-       .endm   // window_spill_function
-
-/*----------------------------------------------------------------------
- *  window_spill_common
- *
- *  Common code used by any number of invocations of the window_spill##
- *  and window_spill_function macros.
- *
- *  Must be instantiated exactly once within a given assembly unit,
- *  within call/j range of and same section as window_spill##
- *  macro invocations for that assembly unit.
- *  (Is automatically instantiated by the window_spill_function macro.)
- */
-
-       .macro  window_spill_common
-#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)
-       .ifndef .L__wdwspill_defined
-# if XCHAL_NUM_AREGS >= 64
-.L__wdwspill_assist60:
-       entry   sp, 32
-       call8   .L__wdwspill_assist52
-       retw
-.L__wdwspill_assist56:
-       entry   sp, 16
-       call4   .L__wdwspill_assist52
-       retw
-.L__wdwspill_assist52:
-       entry   sp, 48
-       call12  .L__wdwspill_assist40
-       retw
-.L__wdwspill_assist40:
-       entry   sp, 48
-       call12  .L__wdwspill_assist28
-       retw
-# endif
-.L__wdwspill_assist28:
-       entry   sp, 48
-       call12  .L__wdwspill_assist16
-       retw
-.L__wdwspill_assist24:
-       entry   sp, 32
-       call8   .L__wdwspill_assist16
-       retw
-.L__wdwspill_assist20:
-       entry   sp, 16
-       call4   .L__wdwspill_assist16
-       retw
-.L__wdwspill_assist16:
-       entry   sp, 16
-       movi    a15, 0
-       retw
-       .set    .L__wdwspill_defined, 1
-       .endif
-#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */
-       .endm   // window_spill_common
-
-/*----------------------------------------------------------------------
- *  beqi32
- *
- *  macro implements version of beqi for arbitrary 32-bit immidiate value
- *
- *     beqi32 ax, ay, imm32, label
- *
- *  Compares value in register ax with imm32 value and jumps to label if
- *  equal. Clobberes register ay if needed
- *
- */
-   .macro beqi32       ax, ay, imm, label
-    .ifeq ((\imm-1) & ~7)      // 1..8 ?
-               beqi    \ax, \imm, \label
-    .else
-      .ifeq (\imm+1)           // -1 ?
-               beqi    \ax, \imm, \label
-      .else
-        .ifeq (\imm)           // 0 ?
-               beqz    \ax, \label
-        .else
-               //  We could also handle immediates 10,12,16,32,64,128,256
-               //  but it would be a long macro...
-               movi    \ay, \imm
-               beq     \ax, \ay, \label
-        .endif
-      .endif
-    .endif
-   .endm // beqi32
-
-#endif /*XTENSA_COREASM_H*/
-
diff --git a/include/asm-xtensa/xtensa/corebits.h b/include/asm-xtensa/xtensa/corebits.h
deleted file mode 100644 (file)
index e578ade..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef XTENSA_COREBITS_H
-#define XTENSA_COREBITS_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * xtensa/corebits.h - Xtensa Special Register field positions and masks.
- *
- * (In previous releases, these were defined in specreg.h, a generated file.
- *  This file is not generated, i.e. it is processor configuration independent.)
- */
-
-
-/*  EXCCAUSE register fields:  */
-#define EXCCAUSE_EXCCAUSE_SHIFT        0
-#define EXCCAUSE_EXCCAUSE_MASK 0x3F
-/*  Exception causes (mostly incomplete!):  */
-#define EXCCAUSE_ILLEGAL               0
-#define EXCCAUSE_SYSCALL               1
-#define EXCCAUSE_IFETCHERROR           2
-#define EXCCAUSE_LOADSTOREERROR                3
-#define EXCCAUSE_LEVEL1INTERRUPT       4
-#define EXCCAUSE_ALLOCA                        5
-
-/*  PS register fields:  */
-#define PS_WOE_SHIFT           18
-#define PS_WOE_MASK            0x00040000
-#define PS_WOE                 PS_WOE_MASK
-#define PS_CALLINC_SHIFT       16
-#define PS_CALLINC_MASK                0x00030000
-#define PS_CALLINC(n)          (((n)&3)<<PS_CALLINC_SHIFT)     /* n = 0..3 */
-#define PS_OWB_SHIFT           8
-#define PS_OWB_MASK            0x00000F00
-#define PS_OWB(n)              (((n)&15)<<PS_OWB_SHIFT)        /* n = 0..15 (or 0..7) */
-#define PS_RING_SHIFT          6
-#define PS_RING_MASK           0x000000C0
-#define PS_RING(n)             (((n)&3)<<PS_RING_SHIFT)        /* n = 0..3 */
-#define PS_UM_SHIFT            5
-#define PS_UM_MASK             0x00000020
-#define PS_UM                  PS_UM_MASK
-#define PS_EXCM_SHIFT          4
-#define PS_EXCM_MASK           0x00000010
-#define PS_EXCM                        PS_EXCM_MASK
-#define PS_INTLEVEL_SHIFT      0
-#define PS_INTLEVEL_MASK       0x0000000F
-#define PS_INTLEVEL(n)         ((n)&PS_INTLEVEL_MASK)          /* n = 0..15 */
-/*  Backward compatibility (deprecated):  */
-#define PS_PROGSTACK_SHIFT     PS_UM_SHIFT
-#define PS_PROGSTACK_MASK      PS_UM_MASK
-#define PS_PROG_SHIFT          PS_UM_SHIFT
-#define PS_PROG_MASK           PS_UM_MASK
-#define PS_PROG                        PS_UM
-
-/*  DBREAKCn register fields:  */
-#define DBREAKC_MASK_SHIFT             0
-#define DBREAKC_MASK_MASK              0x0000003F
-#define DBREAKC_LOADBREAK_SHIFT                30
-#define DBREAKC_LOADBREAK_MASK         0x40000000
-#define DBREAKC_STOREBREAK_SHIFT       31
-#define DBREAKC_STOREBREAK_MASK                0x80000000
-
-/*  DEBUGCAUSE register fields:  */
-#define DEBUGCAUSE_DEBUGINT_SHIFT      5
-#define DEBUGCAUSE_DEBUGINT_MASK       0x20    /* debug interrupt */
-#define DEBUGCAUSE_BREAKN_SHIFT                4
-#define DEBUGCAUSE_BREAKN_MASK         0x10    /* BREAK.N instruction */
-#define DEBUGCAUSE_BREAK_SHIFT         3
-#define DEBUGCAUSE_BREAK_MASK          0x08    /* BREAK instruction */
-#define DEBUGCAUSE_DBREAK_SHIFT                2
-#define DEBUGCAUSE_DBREAK_MASK         0x04    /* DBREAK match */
-#define DEBUGCAUSE_IBREAK_SHIFT                1
-#define DEBUGCAUSE_IBREAK_MASK         0x02    /* IBREAK match */
-#define DEBUGCAUSE_ICOUNT_SHIFT                0
-#define DEBUGCAUSE_ICOUNT_MASK         0x01    /* ICOUNT would increment to zero */
-
-#endif /*XTENSA_COREBITS_H*/
-
diff --git a/include/asm-xtensa/xtensa/hal.h b/include/asm-xtensa/xtensa/hal.h
deleted file mode 100644 (file)
index d104725..0000000
+++ /dev/null
@@ -1,822 +0,0 @@
-#ifndef XTENSA_HAL_H
-#define XTENSA_HAL_H
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/hal.h -- contains a definition of the
- * Core HAL interface.
- *
- * All definitions in this header file are independent of any specific
- * Xtensa processor configuration.  Thus an OS or other software can
- * include this header file and be compiled into configuration-
- * independent objects that can be distributed and eventually linked
- * to the HAL library (libhal.a) to create a configuration-specific
- * final executable.
- *
- * Certain definitions, however, are release-specific -- such as the
- * XTHAL_RELEASE_xxx macros (or additions made in later releases).
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-/*----------------------------------------------------------------------
-                        Constant Definitions
-                       (shared with assembly)
-  ----------------------------------------------------------------------*/
-
-/*  Software release information (not configuration-specific!):  */
-#define XTHAL_RELEASE_MAJOR    1050
-#define XTHAL_RELEASE_MINOR    0
-#define XTHAL_RELEASE_NAME     "T1050.0-2002-08-06-eng0"
-#define XTHAL_RELEASE_INTERNAL "2002-08-06-eng0"
-#define XTHAL_REL_T1050        1
-#define XTHAL_REL_T1050_0      1
-#define XTHAL_REL_T1050_0_2002 1
-#define XTHAL_REL_T1050_0_2002_08      1
-#define XTHAL_REL_T1050_0_2002_08_06   1
-#define XTHAL_REL_T1050_0_2002_08_06_ENG0      1
-
-/*  HAL version numbers (these names are for backward compatibility):  */
-#define XTHAL_MAJOR_REV                XTHAL_RELEASE_MAJOR
-#define XTHAL_MINOR_REV                XTHAL_RELEASE_MINOR
-/*
- *  A bit of software release history on values of XTHAL_{MAJOR,MINOR}_REV:
- *
- *     Release         MAJOR   MINOR           Comment
- *     =======         =====   =====           =======
- *     T1015.n         n/a     n/a             (HAL not yet available)
- *     T1020.{0,1,2}   0       1               (HAL beta)
- *     T1020.{3,4}     0       2               First release.
- *     T1020.n (n>4)   0       2 or >3         (TBD)
- *     T1030.0         0       1               (HAL beta)
- *     T1030.{1,2}     0       3               Equivalent to first release.
- *     T1030.n (n>=3)  0       >= 3            (TBD)
- *     T1040.n         1040    n               Full CHAL available from T1040.2
- *     T1050.n         1050    n               Current release.
- *
- *
- *  Note:  there is a distinction between the software release with
- *  which something is compiled (accessible using XTHAL_RELEASE_* macros)
- *  and the software release with which the HAL library was compiled
- *  (accessible using Xthal_release_* global variables).  This
- *  distinction is particularly relevant for vendors that distribute
- *  configuration-independent binaries (eg. an OS), where their customer
- *  might link it with a HAL of a different Xtensa software release.
- *  In this case, it may be appropriate for the OS to verify at run-time
- *  whether XTHAL_RELEASE_* and Xthal_release_* are compatible.
- *  [Guidelines as to which release is compatible with which are not
- *  currently provided explicitly, but might be inferred from reading
- *  OSKit documentation for all releases -- compatibility is also highly
- *  dependent on which HAL features are used.  Each release is usually
- *  backward compatible, with very few exceptions if any.]
- *
- *  Notes:
- *     Tornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only.
- *     Tornado 2.0.2 supported in T1040.2+, and T1050.
- *     Compile-time HAL port of NucleusPlus supported by T1040.2+ and T1050.
- */
-
-
-/*
- *  Architectural limits, independent of configuration.
- *  Note that these are ISA-defined limits, not micro-architecture implementation
- *  limits enforced by the Xtensa Processor Generator (which may be stricter than
- *  these below).
- */
-#define XTHAL_MAX_CPS          8       /* max number of coprocessors (0..7) */
-#define XTHAL_MAX_INTERRUPTS   32      /* max number of interrupts (0..31) */
-#define XTHAL_MAX_INTLEVELS    16      /* max number of interrupt levels (0..15) */
-                                       /* (as of T1040, implementation limit is 7: 0..6) */
-#define XTHAL_MAX_TIMERS       4       /* max number of timers (CCOMPARE0..CCOMPARE3) */
-                                       /* (as of T1040, implementation limit is 3: 0..2) */
-
-/*  Misc:  */
-#define XTHAL_LITTLEENDIAN             0
-#define XTHAL_BIGENDIAN                        1
-
-
-/*  Interrupt types:  */
-#define XTHAL_INTTYPE_UNCONFIGURED     0
-#define XTHAL_INTTYPE_SOFTWARE         1
-#define XTHAL_INTTYPE_EXTERN_EDGE      2
-#define XTHAL_INTTYPE_EXTERN_LEVEL     3
-#define XTHAL_INTTYPE_TIMER            4
-#define XTHAL_INTTYPE_NMI              5
-#define XTHAL_MAX_INTTYPES             6       /* number of interrupt types */
-
-/*  Timer related:  */
-#define XTHAL_TIMER_UNCONFIGURED       -1      /* Xthal_timer_interrupt[] value for non-existent timers */
-#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED        /* (for backwards compatibility only) */
-
-
-/*  Access Mode bits (tentative):  */  /* bit abbr unit short_name       PPC equ - Description */
-#define XTHAL_AMB_EXCEPTION    0       /* 001 E EX fls: EXception        none    - generate exception on any access (aka "illegal") */
-#define XTHAL_AMB_HITCACHE     1       /* 002 C CH fls: use Cache on Hit ~(I CI) - use cache on hit -- way from tag match [or H HC, or U UC] (ISA: same, except for Isolate case) */
-#define XTHAL_AMB_ALLOCATE     2       /* 004 A AL fl?: ALlocate         none    - refill cache on miss -- way from LRU [or F FI fill] (ISA: Read/Write Miss Refill) */
-#define XTHAL_AMB_WRITETHRU    3       /* 008 W WT --s: WriteThrough     W WT    - store immediately to memory (ISA: same) */
-#define XTHAL_AMB_ISOLATE      4       /* 010 I IS fls: ISolate          none    - use cache regardless of hit-vs-miss -- way from vaddr (ISA: use-cache-on-miss+hit) */
-#define XTHAL_AMB_GUARD                5       /* 020 G GU ?l?: GUard            G *     - non-speculative; spec/replay refs not permitted */
-#if 0
-#define XTHAL_AMB_ORDERED      x       /* 000 O OR fls: ORdered          G *     - mem accesses cannot be out of order */
-#define XTHAL_AMB_FUSEWRITES   x       /* 000 F FW --s: FuseWrites       none    - allow combining/merging multiple writes (to same datapath data unit) into one (implied by writeback) */
-#define XTHAL_AMB_COHERENT     x       /* 000 M MC fl?: Mem/MP Coherent  M       - on reads, other CPUs/bus-masters may need to supply data */
-#define XTHAL_AMB_TRUSTED      x       /* 000 T TR ?l?: TRusted          none    - memory will not bus error (if it does, handle as fatal imprecise interrupt) */
-#define XTHAL_AMB_PREFETCH     x       /* 000 P PR fl?: PRefetch         none    - on refill, read line+1 into prefetch buffers */
-#define XTHAL_AMB_STREAM       x       /* 000 S ST ???: STreaming        none    - access one of N stream buffers */
-#endif /*0*/
-
-#define XTHAL_AM_EXCEPTION     (1<<XTHAL_AMB_EXCEPTION)
-#define XTHAL_AM_HITCACHE      (1<<XTHAL_AMB_HITCACHE)
-#define XTHAL_AM_ALLOCATE      (1<<XTHAL_AMB_ALLOCATE)
-#define XTHAL_AM_WRITETHRU     (1<<XTHAL_AMB_WRITETHRU)
-#define XTHAL_AM_ISOLATE       (1<<XTHAL_AMB_ISOLATE)
-#define XTHAL_AM_GUARD         (1<<XTHAL_AMB_GUARD)
-#if 0
-#define XTHAL_AM_ORDERED       (1<<XTHAL_AMB_ORDERED)
-#define XTHAL_AM_FUSEWRITES    (1<<XTHAL_AMB_FUSEWRITES)
-#define XTHAL_AM_COHERENT      (1<<XTHAL_AMB_COHERENT)
-#define XTHAL_AM_TRUSTED       (1<<XTHAL_AMB_TRUSTED)
-#define XTHAL_AM_PREFETCH      (1<<XTHAL_AMB_PREFETCH)
-#define XTHAL_AM_STREAM                (1<<XTHAL_AMB_STREAM)
-#endif /*0*/
-
-/*
- *  Allowed Access Modes (bit combinations).
- *
- *  Columns are:
- *  "FOGIWACE"
- *     Access mode bits (see XTHAL_AMB_xxx above).
- *     <letter> = bit is set
- *     '-'      = bit is clear
- *     '.'      = bit is irrelevant / don't care, as follows:
- *                     E=1 makes all others irrelevant
- *                     W,F relevant only for stores
- *  "2345"
- *     Indicates which Xtensa releases support the corresponding
- *     access mode.  Releases for each character column are:
- *             2 = prior to T1020.2:   T1015 (V1.5), T1020.0, T1020.1
- *             3 = T1020.2 and later:  T1020.2+, T1030
- *             4 = T1040
- *             5 = T1050 (maybe)
- *     And the character column contents are:
- *             <number> = support by release(s)
- *             "." = unsupported by release(s)
- *             "?" = support unknown
- */
-                                       /* FOGIWACE 2345 */
-/*  For instruction fetch:  */
-#define XTHAL_FAM_EXCEPTION    0x001   /* .......E 2345 exception */
-#define XTHAL_FAM_ISOLATE      0x012   /* .--I.-C- .... isolate */
-#define XTHAL_FAM_BYPASS       0x000   /* .---.--- 2345 bypass */
-#define XTHAL_FAM_NACACHED     0x002   /* .---.-C- .... cached no-allocate (frozen) */
-#define XTHAL_FAM_CACHED       0x006   /* .---.AC- 2345 cached */
-/*  For data load:  */
-#define XTHAL_LAM_EXCEPTION    0x001   /* .......E 2345 exception */
-#define XTHAL_LAM_ISOLATE      0x012   /* .--I.-C- 2345 isolate */
-#define XTHAL_LAM_BYPASS       0x000   /* .O--.--- 2... bypass speculative */
-#define XTHAL_LAM_BYPASSG      0x020   /* .OG-.--- .345 bypass guarded */
-#define XTHAL_LAM_NACACHED     0x002   /* .O--.-C- 2... cached no-allocate speculative */
-#define XTHAL_LAM_NACACHEDG    0x022   /* .OG-.-C- .345 cached no-allocate guarded */
-#define XTHAL_LAM_CACHED       0x006   /* .---.AC- 2345 cached speculative */
-#define XTHAL_LAM_CACHEDG      0x026   /* .?G-.AC- .... cached guarded */
-/*  For data store:  */
-#define XTHAL_SAM_EXCEPTION    0x001   /* .......E 2345 exception */
-#define XTHAL_SAM_ISOLATE      0x032   /* .-GI--C- 2345 isolate */
-#define XTHAL_SAM_BYPASS       0x028   /* -OG-W--- 2345 bypass */
-/*efine XTHAL_SAM_BYPASSF      0x028*/ /* F-G-W--- ...? bypass write-combined */
-#define XTHAL_SAM_WRITETHRU    0x02A   /* -OG-W-C- 234? writethrough */
-/*efine XTHAL_SAM_WRITETHRUF   0x02A*/ /* F-G-W-C- ...5 writethrough write-combined */
-#define XTHAL_SAM_WRITEALLOC   0x02E   /* -OG-WAC- ...? writethrough-allocate */
-/*efine XTHAL_SAM_WRITEALLOCF  0x02E*/ /* F-G-WAC- ...? writethrough-allocate write-combined */
-#define XTHAL_SAM_WRITEBACK    0x026   /* F-G--AC- ...5 writeback */
-
-#if 0
-/*
-    Cache attribute encoding for CACHEATTR (per ISA):
-    (Note:  if this differs from ISA Ref Manual, ISA has precedence)
-
-       Inst-fetches    Loads           Stores
-       -------------   ------------    -------------
-0x0    FCA_EXCEPTION  ?LCA_NACACHED_G* SCA_WRITETHRU   "uncached"
-0x1    FCA_CACHED      LCA_CACHED      SCA_WRITETHRU   cached
-0x2    FCA_BYPASS      LCA_BYPASS_G*   SCA_BYPASS      bypass
-0x3    FCA_CACHED      LCA_CACHED      SCA_WRITEALLOCF write-allocate
-                    or LCA_EXCEPTION   SCA_EXCEPTION   (if unimplemented)
-0x4    FCA_CACHED      LCA_CACHED      SCA_WRITEBACK   write-back
-                    or LCA_EXCEPTION   SCA_EXCEPTION   (if unimplemented)
-0x5..D FCA_EXCEPTION   LCA_EXCEPTION   SCA_EXCEPTION   (reserved)
-0xE    FCA_EXCEPTION   LCA_ISOLATE     SCA_ISOLATE     isolate
-0xF    FCA_EXCEPTION   LCA_EXCEPTION   SCA_EXCEPTION   illegal
-     *  Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G)
-*/
-#endif /*0*/
-
-
-#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*----------------------------------------------------------------------
-                            HAL
-  ----------------------------------------------------------------------*/
-
-/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */
-extern const unsigned int Xthal_rev_no;
-
-
-/*----------------------------------------------------------------------
-                       Processor State
-  ----------------------------------------------------------------------*/
-/* save & restore the extra processor state */
-extern void xthal_save_extra(void *base);
-extern void xthal_restore_extra(void *base);
-
-extern void xthal_save_cpregs(void *base, int);
-extern void xthal_restore_cpregs(void *base, int);
-
-/*extern void xthal_save_all_extra(void *base);*/
-/*extern void xthal_restore_all_extra(void *base);*/
-
-/* space for processor state */
-extern const unsigned int Xthal_extra_size;
-extern const unsigned int Xthal_extra_align;
-/* space for TIE register files */
-extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS];
-extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS];
-
-/* total of space for the processor state (for Tor2) */
-extern const unsigned int Xthal_all_extra_size;
-extern const unsigned int Xthal_all_extra_align;
-
-/* initialize the extra processor */
-/*extern void xthal_init_extra(void);*/
-/* initialize the TIE coprocessor */
-/*extern void xthal_init_cp(int);*/
-
-/* initialize the extra processor */
-extern void xthal_init_mem_extra(void *);
-/* initialize the TIE coprocessor */
-extern void xthal_init_mem_cp(void *, int);
-
-/* validate & invalidate the TIE register file */
-extern void xthal_validate_cp(int);
-extern void xthal_invalidate_cp(int);
-
-/* the number of TIE coprocessors contiguous from zero (for Tor2) */
-extern const unsigned int Xthal_num_coprocessors;
-
-/* actual number of coprocessors */
-extern const unsigned char Xthal_cp_num;
-/* index of highest numbered coprocessor, plus one */
-extern const unsigned char Xthal_cp_max;
-/* index of highest allowed coprocessor number, per cfg, plus one */
-/*extern const unsigned char Xthal_cp_maxcfg;*/
-/* bitmask of which coprocessors are present */
-extern const unsigned int  Xthal_cp_mask;
-
-/* read and write cpenable register */
-extern void xthal_set_cpenable(unsigned);
-extern unsigned xthal_get_cpenable(void);
-
-/* read & write extra state register */
-/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/
-/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/
-
-/* read & write a TIE coprocessor register */
-/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/
-/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/
-
-/* return coprocessor number based on register */
-/*extern int xthal_which_cp(unsigned reg);*/
-
-/*----------------------------------------------------------------------
-                               Interrupts
-  ----------------------------------------------------------------------*/
-
-/* the number of interrupt levels */
-extern const unsigned char Xthal_num_intlevels;
-/* the number of interrupts */
-extern const unsigned char Xthal_num_interrupts;
-
-/* mask for level of interrupts */
-extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS];
-/* mask for level 0 to N interrupts */
-extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS];
-
-/* level of each interrupt */
-extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS];
-
-/* type per interrupt */
-extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS];
-
-/* masks of each type of interrupt */
-extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES];
-
-/* interrupt numbers assigned to each timer interrupt */
-extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS];
-
-/***  Virtual interrupt prioritization:  ***/
-
-/*  Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities:  */
-extern unsigned        xthal_vpri_to_intlevel(unsigned vpri);
-extern unsigned        xthal_intlevel_to_vpri(unsigned intlevel);
-
-/*  Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints:  */
-extern unsigned        xthal_int_enable(unsigned);
-extern unsigned        xthal_int_disable(unsigned);
-
-/*  Set/get virtual priority of an interrupt:  */
-extern int     xthal_set_int_vpri(int intnum, int vpri);
-extern int     xthal_get_int_vpri(int intnum);
-
-/*  Set/get interrupt lockout level for exclusive access to virtual priority data structures:  */
-extern void    xthal_set_vpri_locklevel(unsigned intlevel);
-extern unsigned        xthal_get_vpri_locklevel(void);
-
-/*  Set/get current virtual interrupt priority:  */
-extern unsigned        xthal_set_vpri(unsigned vpri);
-extern unsigned        xthal_get_vpri(unsigned vpri);
-extern unsigned        xthal_set_vpri_intlevel(unsigned intlevel);
-extern unsigned        xthal_set_vpri_lock(void);
-
-
-
-/*----------------------------------------------------------------------
-                       Generic Interrupt Trampolining Support
-  ----------------------------------------------------------------------*/
-
-typedef void (XtHalVoidFunc)(void);
-
-/*
- *  Bitmask of interrupts currently trampolining down:
- */
-extern unsigned Xthal_tram_pending;
-
-/*
- *  Bitmask of which interrupts currently trampolining down
- *  synchronously are actually enabled; this bitmask is necessary
- *  because INTENABLE cannot hold that state (sync-trampolining
- *  interrupts must be kept disabled while trampolining);
- *  in the current implementation, any bit set here is not set
- *  in INTENABLE, and vice-versa; once a sync-trampoline is
- *  handled (at level one), its enable bit must be moved from
- *  here to INTENABLE:
- */
-extern unsigned Xthal_tram_enabled;
-
-/*
- *  Bitmask of interrupts configured for sync trampolining:
- */
-extern unsigned Xthal_tram_sync;
-
-
-/*  Trampoline support functions:  */
-extern unsigned  xthal_tram_pending_to_service( void );
-extern void      xthal_tram_done( unsigned serviced_mask );
-extern int       xthal_tram_set_sync( int intnum, int sync );
-extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn );
-
-/*  INTENABLE,INTREAD,INTSET,INTCLEAR register access functions:  */
-extern unsigned  xthal_get_intenable( void );
-extern void      xthal_set_intenable( unsigned );
-extern unsigned  xthal_get_intread( void );
-extern void      xthal_set_intset( unsigned );
-extern void      xthal_set_intclear( unsigned );
-
-
-/*----------------------------------------------------------------------
-                               Register Windows
-  ----------------------------------------------------------------------*/
-
-/* number of registers in register window */
-extern const unsigned int  Xthal_num_aregs;
-extern const unsigned char Xthal_num_aregs_log2;
-
-/*  This spill any live register windows (other than the caller's):  */
-extern void      xthal_window_spill( void );
-
-
-/*----------------------------------------------------------------------
-                               Cache
-  ----------------------------------------------------------------------*/
-
-/* size of the cache lines in log2(bytes) */
-extern const unsigned char Xthal_icache_linewidth;
-extern const unsigned char Xthal_dcache_linewidth;
-/* size of the cache lines in bytes */
-extern const unsigned short Xthal_icache_linesize;
-extern const unsigned short Xthal_dcache_linesize;
-/* number of cache sets in log2(lines per way) */
-extern const unsigned char Xthal_icache_setwidth;
-extern const unsigned char Xthal_dcache_setwidth;
-/* cache set associativity (number of ways) */
-extern const unsigned int  Xthal_icache_ways;
-extern const unsigned int  Xthal_dcache_ways;
-/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */
-extern const unsigned int  Xthal_icache_size;
-extern const unsigned int  Xthal_dcache_size;
-/* cache features */
-extern const unsigned char Xthal_dcache_is_writeback;
-extern const unsigned char Xthal_icache_line_lockable;
-extern const unsigned char Xthal_dcache_line_lockable;
-
-/* cache attribute register control (used by other HAL routines) */
-extern unsigned xthal_get_cacheattr( void );
-extern unsigned xthal_get_icacheattr( void );
-extern unsigned xthal_get_dcacheattr( void );
-extern void     xthal_set_cacheattr( unsigned );
-extern void     xthal_set_icacheattr( unsigned );
-extern void     xthal_set_dcacheattr( unsigned );
-
-/* initialize cache support (must be called once at startup, before all other cache calls) */
-/*extern void xthal_cache_startinit( void );*/
-/* reset caches */
-/*extern void xthal_icache_reset( void );*/
-/*extern void xthal_dcache_reset( void );*/
-/* enable caches */
-extern void xthal_icache_enable( void );       /* DEPRECATED */
-extern void xthal_dcache_enable( void );       /* DEPRECATED */
-/* disable caches */
-extern void xthal_icache_disable( void );      /* DEPRECATED */
-extern void xthal_dcache_disable( void );      /* DEPRECATED */
-
-/* invalidate the caches */
-extern void xthal_icache_all_invalidate( void );
-extern void xthal_dcache_all_invalidate( void );
-extern void xthal_icache_region_invalidate( void *addr, unsigned size );
-extern void xthal_dcache_region_invalidate( void *addr, unsigned size );
-extern void xthal_icache_line_invalidate(void *addr);
-extern void xthal_dcache_line_invalidate(void *addr);
-/* write dirty data back */
-extern void xthal_dcache_all_writeback( void );
-extern void xthal_dcache_region_writeback( void *addr, unsigned size );
-extern void xthal_dcache_line_writeback(void *addr);
-/* write dirty data back and invalidate */
-extern void xthal_dcache_all_writeback_inv( void );
-extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size );
-extern void xthal_dcache_line_writeback_inv(void *addr);
-/* prefetch and lock specified memory range into cache */
-extern void xthal_icache_region_lock( void *addr, unsigned size );
-extern void xthal_dcache_region_lock( void *addr, unsigned size );
-extern void xthal_icache_line_lock(void *addr);
-extern void xthal_dcache_line_lock(void *addr);
-/* unlock from cache */
-extern void xthal_icache_all_unlock( void );
-extern void xthal_dcache_all_unlock( void );
-extern void xthal_icache_region_unlock( void *addr, unsigned size );
-extern void xthal_dcache_region_unlock( void *addr, unsigned size );
-extern void xthal_icache_line_unlock(void *addr);
-extern void xthal_dcache_line_unlock(void *addr);
-
-
-/* sync icache and memory */
-extern void xthal_icache_sync( void );
-/* sync dcache and memory */
-extern void xthal_dcache_sync( void );
-
-/*----------------------------------------------------------------------
-                               Debug
-  ----------------------------------------------------------------------*/
-
-/*  1 if debug option configured, 0 if not:  */
-extern const int Xthal_debug_configured;
-
-/*  Number of instruction and data break registers:  */
-extern const int Xthal_num_ibreak;
-extern const int Xthal_num_dbreak;
-
-/*  Set (plant) and remove software breakpoint, both synchronizing cache:  */
-extern unsigned int xthal_set_soft_break(void *addr);
-extern void         xthal_remove_soft_break(void *addr, unsigned int);
-
-
-/*----------------------------------------------------------------------
-                               Disassembler
-  ----------------------------------------------------------------------*/
-
-/*  Max expected size of the return buffer for a disassembled instruction (hint only):  */
-#define XTHAL_DISASM_BUFSIZE   80
-
-/*  Disassembly option bits for selecting what to return:  */
-#define XTHAL_DISASM_OPT_ADDR  0x0001  /* display address */
-#define XTHAL_DISASM_OPT_OPHEX 0x0002  /* display opcode bytes in hex */
-#define XTHAL_DISASM_OPT_OPCODE        0x0004  /* display opcode name (mnemonic) */
-#define XTHAL_DISASM_OPT_PARMS 0x0008  /* display parameters */
-#define XTHAL_DISASM_OPT_ALL   0x0FFF  /* display everything */
-
-/* routine to get a string for the disassembled instruction */
-extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr,
-                      char *buffer, unsigned buflen, unsigned options );
-
-/* routine to get the size of the next instruction. Returns 0 for
-   illegal instruction */
-extern int xthal_disassemble_size( unsigned char *instr_buf );
-
-
-/*----------------------------------------------------------------------
-                               Core Counter
-  ----------------------------------------------------------------------*/
-
-/* counter info */
-extern const unsigned char Xthal_have_ccount;  /* set if CCOUNT register present */
-extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */
-
-/* get CCOUNT register (if not present return 0) */
-extern unsigned xthal_get_ccount(void);
-
-/* set and get CCOMPAREn registers (if not present, get returns 0) */
-extern void     xthal_set_ccompare(int, unsigned);
-extern unsigned xthal_get_ccompare(int);
-
-
-/*----------------------------------------------------------------------
-                       Instruction/Data RAM/ROM Access
-  ----------------------------------------------------------------------*/
-
-extern void* xthal_memcpy(void *dst, const void *src, unsigned len);
-extern void* xthal_bcopy(const void *src, void *dst, unsigned len);
-
-/*----------------------------------------------------------------------
-                           MP Synchronization
-  ----------------------------------------------------------------------*/
-extern int      xthal_compare_and_set( int *addr, int test_val, int compare_val );
-extern unsigned xthal_get_prid( void );
-
-/*extern const char  Xthal_have_s32c1i;*/
-extern const unsigned char Xthal_have_prid;
-
-
-/*----------------------------------------------------------------------
-                             Miscellaneous
-  ----------------------------------------------------------------------*/
-
-extern const unsigned int  Xthal_release_major;
-extern const unsigned int  Xthal_release_minor;
-extern const char * const  Xthal_release_name;
-extern const char * const  Xthal_release_internal;
-
-extern const unsigned char Xthal_memory_order;
-extern const unsigned char Xthal_have_windowed;
-extern const unsigned char Xthal_have_density;
-extern const unsigned char Xthal_have_booleans;
-extern const unsigned char Xthal_have_loops;
-extern const unsigned char Xthal_have_nsa;
-extern const unsigned char Xthal_have_minmax;
-extern const unsigned char Xthal_have_sext;
-extern const unsigned char Xthal_have_clamps;
-extern const unsigned char Xthal_have_mac16;
-extern const unsigned char Xthal_have_mul16;
-extern const unsigned char Xthal_have_fp;
-extern const unsigned char Xthal_have_speculation;
-extern const unsigned char Xthal_have_exceptions;
-extern const unsigned char Xthal_xea_version;
-extern const unsigned char Xthal_have_interrupts;
-extern const unsigned char Xthal_have_highlevel_interrupts;
-extern const unsigned char Xthal_have_nmi;
-
-extern const unsigned short Xthal_num_writebuffer_entries;
-
-extern const unsigned int  Xthal_build_unique_id;
-/*  Release info for hardware targeted by software upgrades:  */
-extern const unsigned int  Xthal_hw_configid0;
-extern const unsigned int  Xthal_hw_configid1;
-extern const unsigned int  Xthal_hw_release_major;
-extern const unsigned int  Xthal_hw_release_minor;
-extern const char * const  Xthal_hw_release_name;
-extern const char * const  Xthal_hw_release_internal;
-
-
-/*  Internal memories...  */
-
-extern const unsigned char Xthal_num_instrom;
-extern const unsigned char Xthal_num_instram;
-extern const unsigned char Xthal_num_datarom;
-extern const unsigned char Xthal_num_dataram;
-extern const unsigned char Xthal_num_xlmi;
-extern const unsigned int  Xthal_instrom_vaddr[1];
-extern const unsigned int  Xthal_instrom_paddr[1];
-extern const unsigned int  Xthal_instrom_size [1];
-extern const unsigned int  Xthal_instram_vaddr[1];
-extern const unsigned int  Xthal_instram_paddr[1];
-extern const unsigned int  Xthal_instram_size [1];
-extern const unsigned int  Xthal_datarom_vaddr[1];
-extern const unsigned int  Xthal_datarom_paddr[1];
-extern const unsigned int  Xthal_datarom_size [1];
-extern const unsigned int  Xthal_dataram_vaddr[1];
-extern const unsigned int  Xthal_dataram_paddr[1];
-extern const unsigned int  Xthal_dataram_size [1];
-extern const unsigned int  Xthal_xlmi_vaddr[1];
-extern const unsigned int  Xthal_xlmi_paddr[1];
-extern const unsigned int  Xthal_xlmi_size [1];
-
-
-
-/*----------------------------------------------------------------------
-                         Memory Management Unit
-  ----------------------------------------------------------------------*/
-
-extern const unsigned char Xthal_have_spanning_way;
-extern const unsigned char Xthal_have_identity_map;
-extern const unsigned char Xthal_have_mimic_cacheattr;
-extern const unsigned char Xthal_have_xlt_cacheattr;
-extern const unsigned char Xthal_have_cacheattr;
-extern const unsigned char Xthal_have_tlbs;
-
-extern const unsigned char Xthal_mmu_asid_bits;                /* 0 .. 8 */
-extern const unsigned char Xthal_mmu_asid_kernel;
-extern const unsigned char Xthal_mmu_rings;            /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */
-extern const unsigned char Xthal_mmu_ring_bits;
-extern const unsigned char Xthal_mmu_sr_bits;
-extern const unsigned char Xthal_mmu_ca_bits;
-extern const unsigned int  Xthal_mmu_max_pte_page_size;
-extern const unsigned int  Xthal_mmu_min_pte_page_size;
-
-extern const unsigned char Xthal_itlb_way_bits;
-extern const unsigned char Xthal_itlb_ways;
-extern const unsigned char Xthal_itlb_arf_ways;
-extern const unsigned char Xthal_dtlb_way_bits;
-extern const unsigned char Xthal_dtlb_ways;
-extern const unsigned char Xthal_dtlb_arf_ways;
-
-/*  Convert between virtual and physical addresses (through static maps only):  */
-/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/
-extern int  xthal_static_v2p( unsigned vaddr, unsigned *paddrp );
-extern int  xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached );
-
-#if 0
-/*******************   EXPERIMENTAL AND TENTATIVE ONLY   ********************/
-
-#define XTHAL_MMU_PAGESZ_COUNT_MAX     8       /* maximum number of different page sizes */
-extern const char      Xthal_mmu_pagesz_count;         /* 0 .. 8               number of different page sizes configured */
-
-/*  Note:  the following table doesn't necessarily have page sizes in increasing order: */
-extern const char      Xthal_mmu_pagesz_log2[XTHAL_MMU_PAGESZ_COUNT_MAX];      /* 10 .. 28 (0 past count) */
-
-/*  Sorted (increasing) table of page sizes, that indexes into the above table: */
-extern const char      Xthal_mmu_pagesz_sorted[XTHAL_MMU_PAGESZ_COUNT_MAX];    /* 0 .. 7 (0 past count) */
-
-/*u32  Xthal_virtual_exceptions;*/     /* bitmask of which exceptions execute in virtual mode... */
-
-extern const char      Xthal_mmu_pte_pagesz_log2_min;  /* ?? minimum page size in PTEs */
-extern const char      Xthal_mmu_pte_pagesz_log2_max;  /* ?? maximum page size in PTEs */
-
-/*  Cache Attribute Bits Implemented by the Cache (part of the cache abstraction) */
-extern const char      Xthal_icache_fca_bits_implemented;      /* ITLB/UTLB only! */
-extern const char      Xthal_dcache_lca_bits_implemented;      /* DTLB/UTLB only! */
-extern const char      Xthal_dcache_sca_bits_implemented;      /* DTLB/UTLB only! */
-
-/*  Per TLB Parameters (Instruction, Data, Unified)  */
-struct XtHalMmuTlb     Xthal_itlb;     /* description of MMU I-TLB generic features */
-struct XtHalMmuTlb     Xthal_dtlb;     /* description of MMU D-TLB generic features */
-struct XtHalMmuTlb     Xthal_utlb;     /* description of MMU U-TLB generic features */
-
-#define XTHAL_MMU_WAYS_MAX     8       /* maximum number of ways (associativities) for each TLB */
-
-/*  Structure for common information described for each possible TLB (instruction, data and unified): */
-typedef struct XtHalMmuTlb {
-    u8         va_bits;                /* 32           (number of virtual address bits) */
-    u8         pa_bits;                /* 32           (number of physical address bits) */
-    bool       tlb_va_indexed;         /* 1    (set if TLB is indexed by virtual address) */
-    bool       tlb_va_tagged;          /* 0    (set if TLB is tagged by virtual address) */
-    bool       cache_va_indexed;       /* 1    (set if cache is indexed by virtual address) */
-    bool       cache_va_tagged;        /* 0    (set if cache is tagged by virtual address) */
-    /*bool     (whether page tables are traversed in vaddr sorted order, paddr sorted order, ...) */
-    /*u8       (set of available page attribute bits, other than cache attribute bits defined above) */
-    /*u32      (various masks for pages, MMU table/TLB entries, etc.) */
-    u8         way_count;              /* 0 .. 8       (number of ways, a.k.a. associativities, for this TLB) */
-    XtHalMmuTlbWay *   ways[XTHAL_MMU_WAYS_MAX];       /* pointers to per-way parms for each way */
-} XtHalMmuTlb;
-
-/*  Per TLB Way (Per Associativity) Parameters  */
-typedef struct XtHalMmuTlbWay {
-     u32       index_count_log2;       /* 0 .. 4 */
-     u32       pagesz_mask;            /* 0 .. 2^pagesz_count - 1      (each bit corresponds to a size */
-                                       /*              defined in the Xthal_mmu_pagesz_log2[] table) */
-     u32       vpn_const_mask;
-     u32       vpn_const_value;
-     u64       ppn_const_mask;         /* future may support pa_bits > 32 */
-     u64       ppn_const_value;
-     u32       ppn_id_mask;            /* paddr bits taken directly from vaddr */
-     bool      backgnd_match;          /* 0 or 1 */
-     /*  These are defined in terms of the XTHAL_CACHE_xxx bits: */
-     u8        fca_const_mask;         /* ITLB/UTLB only! */
-     u8        fca_const_value;        /* ITLB/UTLB only! */
-     u8        lca_const_mask;         /* DTLB/UTLB only! */
-     u8        lca_const_value;        /* DTLB/UTLB only! */
-     u8        sca_const_mask;         /* DTLB/UTLB only! */
-     u8        sca_const_value;        /* DTLB/UTLB only! */
-     /*  These define an encoding that map 5 bits in TLB and PTE entries to */
-     /*  8 bits (FCA, ITLB), 16 bits (LCA+SCA, DTLB) or 24 bits (FCA+LCA+SCA, UTLB): */
-     /*  (they may be moved to struct XtHalMmuTlb) */
-     u8                ca_bits;                /* number of bits in TLB/PTE entries for cache attributes */
-     u32 *     ca_map;                 /* pointer to array of 2^ca_bits entries of FCA+LCA+SCA bits */
-} XtHalMmuTlbWay;
-
-/*
- *  The way to determine whether protection support is present in core
- *  is to [look at Xthal_mmu_rings ???].
- *  Give info on memory requirements for MMU tables and other in-memory
- *  data structures (globally, per task, base and per page, etc.) - whatever bounds can be calculated.
- */
-
-
-/*  Default vectors:  */
-xthal_immu_fetch_miss_vector
-xthal_dmmu_load_miss_vector
-xthal_dmmu_store_miss_vector
-
-/*  Functions called when a fault is detected:  */
-typedef void (XtHalMmuFaultFunc)( unsigned vaddr, ...context... );
-/*  Or, */
-/*     a? = vaddr */
-/*     a? = context... */
-/*     PS.xxx = xxx */
-XtHalMMuFaultFunc *Xthal_immu_fetch_fault_func;
-XtHalMMuFaultFunc *Xthal_dmmu_load_fault_func;
-XtHalMMuFaultFunc *Xthal_dmmu_store_fault_func;
-
-/*  Default Handlers:  */
-/*  The user and/or kernel exception handlers may jump to these handlers to handle the relevant exceptions,
- *  according to the value of EXCCAUSE.  The exact register state on entry to these handlers is TBD.  */
-/*  When multiple TLB entries match (hit) on the same access:  */
-xthal_immu_fetch_multihit_handler
-xthal_dmmu_load_multihit_handler
-xthal_dmmu_store_multihit_handler
-/*  Protection violations according to cache attributes, and other cache attribute mismatches:  */
-xthal_immu_fetch_attr_handler
-xthal_dmmu_load_attr_handler
-xthal_dmmu_store_attr_handler
-/*  Protection violations due to insufficient ring level:  */
-xthal_immu_fetch_priv_handler
-xthal_dmmu_load_priv_handler
-xthal_dmmu_store_priv_handler
-/*  Alignment exception handlers (if supported by the particular Xtensa MMU configuration):  */
-xthal_dmmu_load_align_handler
-xthal_dmmu_store_align_handler
-
-/*  Or, alternatively, the OS user and/or kernel exception handlers may simply jump to the
- *  following entry points which will handle any values of EXCCAUSE not handled by the OS:  */
-xthal_user_exc_default_handler
-xthal_kernel_exc_default_handler
-
-#endif /*0*/
-
-#ifdef INCLUDE_DEPRECATED_HAL_CODE
-extern const unsigned char Xthal_have_old_exc_arch;
-extern const unsigned char Xthal_have_mmu;
-extern const unsigned int  Xthal_num_regs;
-extern const unsigned char Xthal_num_iroms;
-extern const unsigned char Xthal_num_irams;
-extern const unsigned char Xthal_num_droms;
-extern const unsigned char Xthal_num_drams;
-extern const unsigned int  Xthal_configid0;
-extern const unsigned int  Xthal_configid1;
-#endif
-
-#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE
-#define XTHAL_24_BIT_BREAK             0x80000000
-#define XTHAL_16_BIT_BREAK             0x40000000
-extern const unsigned short    Xthal_ill_inst_16[16];
-#define XTHAL_DEST_REG         0xf0000000      /* Mask for destination register */
-#define XTHAL_DEST_REG_INST    0x08000000      /* Branch address is in register */
-#define XTHAL_DEST_REL_INST    0x04000000      /* Branch address is relative */
-#define XTHAL_RFW_INST         0x00000800
-#define XTHAL_RFUE_INST                0x00000400
-#define XTHAL_RFI_INST         0x00000200
-#define XTHAL_RFE_INST         0x00000100
-#define XTHAL_RET_INST         0x00000080
-#define XTHAL_BREAK_INST       0x00000040
-#define XTHAL_SYSCALL_INST     0x00000020
-#define XTHAL_LOOP_END         0x00000010      /* Not set by xthal_inst_type */
-#define XTHAL_JUMP_INST                0x00000008      /* Call or jump instruction */
-#define XTHAL_BRANCH_INST      0x00000004      /* Branch instruction */
-#define XTHAL_24_BIT_INST      0x00000002
-#define XTHAL_16_BIT_INST   0x00000001
-typedef struct xthal_state {
-    unsigned   pc;
-    unsigned   ar[16];
-    unsigned   lbeg;
-    unsigned   lend;
-    unsigned   lcount;
-    unsigned   extra_ptr;
-    unsigned   cpregs_ptr[XTHAL_MAX_CPS];
-} XTHAL_STATE;
-extern unsigned int xthal_inst_type(void *addr);
-extern unsigned int xthal_branch_addr(void *addr);
-extern unsigned int xthal_get_npc(XTHAL_STATE *user_state);
-#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */
-
-#ifdef __cplusplus
-}
-#endif
-#endif /*!__ASSEMBLY__ */
-
-#endif /*XTENSA_HAL_H*/
-
diff --git a/include/asm-xtensa/xtensa/simcall.h b/include/asm-xtensa/xtensa/simcall.h
deleted file mode 100644 (file)
index a2b8689..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#ifndef SIMCALL_INCLUDED
-#define SIMCALL_INCLUDED
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/simcall.h  -  Simulator call numbers
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-/*
- *  System call like services offered by the simulator host.
- *  These are modeled after the Linux 2.4 kernel system calls
- *  for Xtensa processors.  However not all system calls and
- *  not all functionality of a given system call are implemented,
- *  or necessarily have well defined or equivalent semantics in
- *  the context of a simulation (as opposed to a Unix kernel).
- *
- *  These services behave largely as if they had been invoked
- *  as a task in the simulator host's operating system
- *  (eg. files accessed are those of the simulator host).
- *  However, these SIMCALLs model a virtual operating system
- *  so that various definitions, bit assignments etc
- *  (eg. open mode bits, errno values, etc) are independent
- *  of the host operating system used to run the simulation.
- *  Rather these definitions are specific to the Xtensa ISS.
- *  This way Xtensa ISA code written to use these SIMCALLs
- *  can (in principle) be simulated on any host.
- *
- *  Up to 6 parameters are passed in registers a3 to a8
- *  (note the 6th parameter isn't passed on the stack,
- *   unlike windowed function calling conventions).
- *  The return value is in a2.  A negative value in the
- *  range -4096 to -1 indicates a negated error code to be
- *  reported in errno with a return value of -1, otherwise
- *  the value in a2 is returned as is.
- */
-
-/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */
-
-#define SYS_nop                0       /* n/a - setup; used to flush register windows */
-#define SYS_exit       1       /*x*/
-#define SYS_fork       2
-#define SYS_read       3       /*x*/
-#define SYS_write      4       /*x*/
-#define SYS_open       5       /*x*/
-#define SYS_close      6       /*x*/
-#define SYS_rename     7       /*x 38 - waitpid */
-#define SYS_creat      8       /*x*/
-#define SYS_link       9       /*x (not implemented on WIN32) */
-#define SYS_unlink     10      /*x*/
-#define SYS_execv      11      /* n/a - execve */
-#define SYS_execve     12      /* 11 - chdir */
-#define SYS_pipe       13      /* 42 - time */
-#define SYS_stat       14      /* 106 - mknod */
-#define SYS_chmod      15
-#define SYS_chown      16      /* 202 - lchown */
-#define SYS_utime      17      /* 30 - break */
-#define SYS_wait       18      /* n/a - oldstat */
-#define SYS_lseek      19      /*x*/
-#define SYS_getpid     20
-#define SYS_isatty     21      /* n/a - mount */
-#define SYS_fstat      22      /* 108 - oldumount */
-#define SYS_time       23      /* 13 - setuid */
-#define SYS_gettimeofday 24    /*x 78 - getuid (not implemented on WIN32) */
-#define SYS_times      25      /*X 43 - stime (Xtensa-specific implementation) */
-#define SYS_socket      26
-#define SYS_sendto      27
-#define SYS_recvfrom    28
-#define SYS_select_one  29      /* not compitible select, one file descriptor at the time */
-#define SYS_bind        30
-#define SYS_ioctl      31
-
-/*
- *  Other...
- */
-#define SYS_iss_argc      1000 /* returns value of argc */
-#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */
-#define SYS_iss_set_argv  1002 /* saves argv & arg strings at given addr */
-
-/*
- * SIMCALLs for the ferret memory debugger. All are invoked by
- * libferret.a ...  ( Xtensa/Target-Libs/ferret )
- */
-#define SYS_ferret           1010
-#define SYS_malloc           1011
-#define SYS_free             1012
-#define SYS_more_heap        1013
-#define SYS_no_heap          1014
-
-
-/*
- *  Extra SIMCALLs for GDB:
- */
-#define SYS_gdb_break         -1       /* invoked by XTOS on user exceptions if EPC points
-                                          to a break.n/break, regardless of cause! */
-#define SYS_xmon_out          -2       /* invoked by XMON: ... */
-#define SYS_xmon_in           -3       /* invoked by XMON: ... */
-#define SYS_xmon_flush        -4       /* invoked by XMON: ... */
-#define SYS_gdb_abort         -5       /* invoked by XTOS in _xtos_panic() */
-#define SYS_gdb_illegal_inst  -6       /* invoked by XTOS for illegal instructions (too deeply) */
-#define SYS_xmon_init         -7       /* invoked by XMON: ... */
-#define SYS_gdb_enter_sktloop -8       /* invoked by XTOS on debug exceptions */
-
-/*
- *  SIMCALLs for vxWorks xtiss BSP:
- */
-#define SYS_setup_ppp_pipes   -83
-#define SYS_log_msg           -84
-
-/*
- *  Test SIMCALLs:
- */
-#define SYS_test_write_state  -100
-#define SYS_test_read_state   -101
-
-/*
- * SYS_select_one specifiers
- */
-#define  XTISS_SELECT_ONE_READ    1
-#define  XTISS_SELECT_ONE_WRITE   2
-#define  XTISS_SELECT_ONE_EXCEPT  3
-
-#endif /* !SIMCALL_INCLUDED */
diff --git a/include/asm-xtensa/xtensa/xt2000-uart.h b/include/asm-xtensa/xtensa/xt2000-uart.h
deleted file mode 100644 (file)
index 0154460..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#ifndef _uart_h_included_
-#define _uart_h_included_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/xt2000-uart.h -- NatSemi PC16552D DUART
- * definitions
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/xt2000.h>
-
-
-/* 16550 UART DEVICE REGISTERS
-   The XT2000 board aligns each register to a 32-bit word but the UART device only uses
-   one byte of the word, which is the least-significant byte regardless of the
-   endianness of the core (ie. byte offset 0 for little-endian and 3 for big-endian).
-   So if using word accesses then endianness doesn't matter.
-   The macros provided here do that.
-*/
-struct uart_dev_s {
-  union {
-    unsigned int rxb;  /* DLAB=0: receive buffer, read-only */
-    unsigned int txb;  /* DLAB=0: transmit buffer, write-only */
-    unsigned int dll;  /* DLAB=1: divisor, least-significant byte latch (was write-only?) */
-  } w0;
-  union {
-    unsigned int ier;  /* DLAB=0: interrupt-enable register (was write-only?) */
-    unsigned int dlm;  /* DLAB=1: divisor, most-significant byte latch (was write-only?) */
-  } w1;
-
-  union {
-    unsigned int isr;  /* DLAB=0: interrupt status register, read-only */
-    unsigned int fcr;  /* DLAB=0: FIFO control register, write-only */
-    unsigned int afr;  /* DLAB=1: alternate function register */
-  } w2;
-
-  unsigned int lcr;    /* line control-register, write-only */
-  unsigned int mcr;    /* modem control-regsiter, write-only */
-  unsigned int lsr;    /* line status register, read-only */
-  unsigned int msr;    /* modem status register, read-only */
-  unsigned int scr;    /* scratch regsiter, read/write */
-};
-
-#define _RXB(u) ((u)->w0.rxb)
-#define _TXB(u) ((u)->w0.txb)
-#define _DLL(u) ((u)->w0.dll)
-#define _IER(u) ((u)->w1.ier)
-#define _DLM(u) ((u)->w1.dlm)
-#define _ISR(u) ((u)->w2.isr)
-#define _FCR(u) ((u)->w2.fcr)
-#define _AFR(u) ((u)->w2.afr)
-#define _LCR(u) ((u)->lcr)
-#define _MCR(u) ((u)->mcr)
-#define _LSR(u) ((u)->lsr)
-#define _MSR(u) ((u)->msr)
-#define _SCR(u) ((u)->scr)
-
-typedef volatile struct uart_dev_s uart_dev_t;
-
-/* IER bits */
-#define RCVR_DATA_REG_INTENABLE 0x01
-#define XMIT_HOLD_REG_INTENABLE    0x02
-#define RCVR_STATUS_INTENABLE   0x04
-#define MODEM_STATUS_INTENABLE     0x08
-
-/* FCR bits */
-#define _FIFO_ENABLE      0x01
-#define RCVR_FIFO_RESET  0x02
-#define XMIT_FIFO_RESET  0x04
-#define DMA_MODE_SELECT  0x08
-#define RCVR_TRIGGER_LSB 0x40
-#define RCVR_TRIGGER_MSB 0x80
-
-/* AFR bits */
-#define AFR_CONC_WRITE 0x01
-#define AFR_BAUDOUT_SEL        0x02
-#define AFR_RXRDY_SEL  0x04
-
-/* ISR bits */
-#define INT_STATUS(r)   ((r)&1)
-#define INT_PRIORITY(r) (((r)>>1)&0x7)
-
-/* LCR bits */
-#define WORD_LENGTH(n)  (((n)-5)&0x3)
-#define STOP_BIT_ENABLE 0x04
-#define PARITY_ENABLE   0x08
-#define EVEN_PARITY     0x10
-#define FORCE_PARITY    0x20
-#define XMIT_BREAK      0x40
-#define DLAB_ENABLE     0x80
-
-/* MCR bits */
-#define _DTR 0x01
-#define _RTS 0x02
-#define _OP1 0x04
-#define _OP2 0x08
-#define LOOP_BACK 0x10
-
-/* LSR Bits */
-#define RCVR_DATA_READY 0x01
-#define OVERRUN_ERROR   0x02
-#define PARITY_ERROR    0x04
-#define FRAMING_ERROR   0x08
-#define BREAK_INTERRUPT 0x10
-#define XMIT_HOLD_EMPTY 0x20
-#define XMIT_EMPTY      0x40
-#define FIFO_ERROR      0x80
-#define RCVR_READY(u)   (_LSR(u)&RCVR_DATA_READY)
-#define XMIT_READY(u)   (_LSR(u)&XMIT_HOLD_EMPTY)
-
-/* MSR bits */
-#define _RDR       0x01
-#define DELTA_DSR 0x02
-#define DELTA_RI  0x04
-#define DELTA_CD  0x08
-#define _CTS       0x10
-#define _DSR       0x20
-#define _RI        0x40
-#define _CD        0x80
-
-/* prototypes */
-void uart_init( uart_dev_t *u, int bitrate );
-void uart_out( uart_dev_t *u, char c );
-void uart_puts( uart_dev_t *u, char *s );
-char uart_in( uart_dev_t *u );
-void uart_enable_rcvr_int( uart_dev_t *u );
-void uart_disable_rcvr_int( uart_dev_t *u );
-
-#ifdef DUART16552_1_VADDR
-/*  DUART present.  */
-#define DUART_1_BASE   (*(uart_dev_t*)DUART16552_1_VADDR)
-#define DUART_2_BASE   (*(uart_dev_t*)DUART16552_2_VADDR)
-#define UART1_PUTS(s)  uart_puts( &DUART_1_BASE, s )
-#define UART2_PUTS(s)  uart_puts( &DUART_2_BASE, s )
-#else
-/*  DUART not configured, use dummy placeholders to allow compiles to work.  */
-#define DUART_1_BASE   (*(uart_dev_t*)0)
-#define DUART_2_BASE   (*(uart_dev_t*)0)
-#define UART1_PUTS(s)
-#define UART2_PUTS(s)
-#endif
-
-/*  Compute 16-bit divisor for baudrate generator, with rounding:  */
-#define DUART_DIVISOR(crystal,speed)   (((crystal)/16 + (speed)/2)/(speed))
-
-#endif /*_uart_h_included_*/
-
diff --git a/include/asm-xtensa/xtensa/xt2000.h b/include/asm-xtensa/xtensa/xt2000.h
deleted file mode 100644 (file)
index 703a450..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-#ifndef _INC_XT2000_H_
-#define _INC_XT2000_H_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- * include/asm-xtensa/xtensa/xt2000.h - Definitions specific to the
- * Tensilica XT2000 Emulation Board
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/config/core.h>
-#include <xtensa/config/system.h>
-
-
-/*
- *  Default assignment of XT2000 devices to external interrupts.
- */
-
-/*  Ethernet interrupt:  */
-#ifdef XCHAL_EXTINT3_NUM
-#define SONIC83934_INTNUM      XCHAL_EXTINT3_NUM
-#define SONIC83934_INTLEVEL    XCHAL_EXTINT3_LEVEL
-#define SONIC83934_INTMASK     XCHAL_EXTINT3_MASK
-#else
-#define SONIC83934_INTMASK     0
-#endif
-
-/*  DUART channel 1 interrupt (P1 - console):  */
-#ifdef XCHAL_EXTINT4_NUM
-#define DUART16552_1_INTNUM    XCHAL_EXTINT4_NUM
-#define DUART16552_1_INTLEVEL  XCHAL_EXTINT4_LEVEL
-#define DUART16552_1_INTMASK   XCHAL_EXTINT4_MASK
-#else
-#define DUART16552_1_INTMASK   0
-#endif
-
-/*  DUART channel 2 interrupt (P2 - 2nd serial port):  */
-#ifdef XCHAL_EXTINT5_NUM
-#define DUART16552_2_INTNUM    XCHAL_EXTINT5_NUM
-#define DUART16552_2_INTLEVEL  XCHAL_EXTINT5_LEVEL
-#define DUART16552_2_INTMASK   XCHAL_EXTINT5_MASK
-#else
-#define DUART16552_2_INTMASK   0
-#endif
-
-/*  FPGA-combined PCI/etc interrupts:  */
-#ifdef XCHAL_EXTINT6_NUM
-#define XT2000_FPGAPCI_INTNUM  XCHAL_EXTINT6_NUM
-#define XT2000_FPGAPCI_INTLEVEL        XCHAL_EXTINT6_LEVEL
-#define XT2000_FPGAPCI_INTMASK XCHAL_EXTINT6_MASK
-#else
-#define XT2000_FPGAPCI_INTMASK 0
-#endif
-
-
-
-/*
- *  Device addresses.
- *
- *  Note:  for endianness-independence, use 32-bit loads and stores for all
- *  register accesses to Ethernet, DUART and LED devices.  Undefined bits
- *  may need to be masked out if needed when reading if the actual register
- *  size is smaller than 32 bits.
- *
- *  Note:  XT2000 bus byte lanes are defined in terms of msbyte and lsbyte
- *  relative to the processor.  So 32-bit registers are accessed consistently
- *  from both big and little endian processors.  However, this means byte
- *  sequences are not consistent between big and little endian processors.
- *  This is fine for RAM, and for ROM if ROM is created for a specific
- *  processor (and thus has correct byte sequences).  However this may be
- *  unexpected for Flash, which might contain a file-system that one wants
- *  to use for multiple processor configurations (eg. the Flash might contain
- *  the Ethernet card's address, endianness-independent application data, etc).
- *  That is, byte sequences written in Flash by a core of a given endianness
- *  will be byte-swapped when seen by a core of the other endianness.
- *  Someone implementing an endianness-independent Flash file system will
- *  likely handle this byte-swapping issue in the Flash driver software.
- */
-
-#define DUART16552_XTAL_FREQ   18432000        /* crystal frequency in Hz */
-#define XTBOARD_FLASH_MAXSIZE  0x4000000       /* 64 MB (max; depends on what is socketed!) */
-#define XTBOARD_EPROM_MAXSIZE  0x0400000       /* 4 MB (max; depends on what is socketed!) */
-#define XTBOARD_EEPROM_MAXSIZE 0x0080000       /* 512 kB (max; depends on what is socketed!) */
-#define XTBOARD_ASRAM_SIZE     0x0100000       /* 1 MB */
-#define XTBOARD_PCI_MEM_SIZE   0x8000000       /* 128 MB (allocated) */
-#define XTBOARD_PCI_IO_SIZE    0x1000000       /* 16 MB (allocated) */
-
-#ifdef XSHAL_IOBLOCK_BYPASS_PADDR
-/*  PCI memory space:  */
-# define XTBOARD_PCI_MEM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x0000000)
-/*  Socketed Flash (eg. 2 x 16-bit devices):  */
-# define XTBOARD_FLASH_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0x8000000)
-/*  PCI I/O space:  */
-# define XTBOARD_PCI_IO_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xC000000)
-/*  V3 PCI interface chip register/config space:  */
-# define XTBOARD_V3PCI_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD000000)
-/*  Bus Interface registers:  */
-# define XTBOARD_BUSINT_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xD010000)
-/*  FPGA registers:  */
-# define XT2000_FPGAREGS_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD020000)
-/*  SONIC SN83934 Ethernet controller/transceiver:  */
-# define SONIC83934_PADDR      (XSHAL_IOBLOCK_BYPASS_PADDR+0xD030000)
-/*  8-character bitmapped LED display:  */
-# define XTBOARD_LED_PADDR     (XSHAL_IOBLOCK_BYPASS_PADDR+0xD040000)
-/*  National-Semi PC16552D DUART:  */
-# define DUART16552_1_PADDR    (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050020)  /* channel 1 (P1 - console) */
-# define DUART16552_2_PADDR    (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050000)  /* channel 2 (P2) */
-/*  Asynchronous Static RAM:  */
-# define XTBOARD_ASRAM_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD400000)
-/*  8-bit EEPROM:  */
-# define XTBOARD_EEPROM_PADDR  (XSHAL_IOBLOCK_BYPASS_PADDR+0xD600000)
-/*  2 x 16-bit EPROMs:  */
-# define XTBOARD_EPROM_PADDR   (XSHAL_IOBLOCK_BYPASS_PADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_BYPASS_PADDR */
-
-/*  These devices might be accessed cached:  */
-#ifdef XSHAL_IOBLOCK_CACHED_PADDR
-# define XTBOARD_PCI_MEM_CACHED_PADDR  (XSHAL_IOBLOCK_CACHED_PADDR+0x0000000)
-# define XTBOARD_FLASH_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0x8000000)
-# define XTBOARD_ASRAM_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0xD400000)
-# define XTBOARD_EEPROM_CACHED_PADDR   (XSHAL_IOBLOCK_CACHED_PADDR+0xD600000)
-# define XTBOARD_EPROM_CACHED_PADDR    (XSHAL_IOBLOCK_CACHED_PADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_CACHED_PADDR */
-
-
-/***  Same thing over again, this time with virtual addresses:  ***/
-
-#ifdef XSHAL_IOBLOCK_BYPASS_VADDR
-/*  PCI memory space:  */
-# define XTBOARD_PCI_MEM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x0000000)
-/*  Socketed Flash (eg. 2 x 16-bit devices):  */
-# define XTBOARD_FLASH_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0x8000000)
-/*  PCI I/O space:  */
-# define XTBOARD_PCI_IO_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xC000000)
-/*  V3 PCI interface chip register/config space:  */
-# define XTBOARD_V3PCI_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD000000)
-/*  Bus Interface registers:  */
-# define XTBOARD_BUSINT_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xD010000)
-/*  FPGA registers:  */
-# define XT2000_FPGAREGS_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD020000)
-/*  SONIC SN83934 Ethernet controller/transceiver:  */
-# define SONIC83934_VADDR      (XSHAL_IOBLOCK_BYPASS_VADDR+0xD030000)
-/*  8-character bitmapped LED display:  */
-# define XTBOARD_LED_VADDR     (XSHAL_IOBLOCK_BYPASS_VADDR+0xD040000)
-/*  National-Semi PC16552D DUART:  */
-# define DUART16552_1_VADDR    (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050020)  /* channel 1 (P1 - console) */
-# define DUART16552_2_VADDR    (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050000)  /* channel 2 (P2) */
-/*  Asynchronous Static RAM:  */
-# define XTBOARD_ASRAM_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD400000)
-/*  8-bit EEPROM:  */
-# define XTBOARD_EEPROM_VADDR  (XSHAL_IOBLOCK_BYPASS_VADDR+0xD600000)
-/*  2 x 16-bit EPROMs:  */
-# define XTBOARD_EPROM_VADDR   (XSHAL_IOBLOCK_BYPASS_VADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_BYPASS_VADDR */
-
-/*  These devices might be accessed cached:  */
-#ifdef XSHAL_IOBLOCK_CACHED_VADDR
-# define XTBOARD_PCI_MEM_CACHED_VADDR  (XSHAL_IOBLOCK_CACHED_VADDR+0x0000000)
-# define XTBOARD_FLASH_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0x8000000)
-# define XTBOARD_ASRAM_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0xD400000)
-# define XTBOARD_EEPROM_CACHED_VADDR   (XSHAL_IOBLOCK_CACHED_VADDR+0xD600000)
-# define XTBOARD_EPROM_CACHED_VADDR    (XSHAL_IOBLOCK_CACHED_VADDR+0xD800000)
-#endif /* XSHAL_IOBLOCK_CACHED_VADDR */
-
-
-/*  System ROM:  */
-#define XTBOARD_ROM_SIZE               XSHAL_ROM_SIZE
-#ifdef XSHAL_ROM_VADDR
-#define XTBOARD_ROM_VADDR              XSHAL_ROM_VADDR
-#endif
-#ifdef XSHAL_ROM_PADDR
-#define XTBOARD_ROM_PADDR              XSHAL_ROM_PADDR
-#endif
-
-/*  System RAM:  */
-#define XTBOARD_RAM_SIZE               XSHAL_RAM_SIZE
-#ifdef XSHAL_RAM_VADDR
-#define XTBOARD_RAM_VADDR              XSHAL_RAM_VADDR
-#endif
-#ifdef XSHAL_RAM_PADDR
-#define XTBOARD_RAM_PADDR              XSHAL_RAM_PADDR
-#endif
-#define XTBOARD_RAM_BYPASS_VADDR       XSHAL_RAM_BYPASS_VADDR
-#define XTBOARD_RAM_BYPASS_PADDR       XSHAL_RAM_BYPASS_PADDR
-
-
-
-/*
- *  Things that depend on device addresses.
- */
-
-
-#define XTBOARD_CACHEATTR_WRITEBACK    XSHAL_XT2000_CACHEATTR_WRITEBACK
-#define XTBOARD_CACHEATTR_WRITEALLOC   XSHAL_XT2000_CACHEATTR_WRITEALLOC
-#define XTBOARD_CACHEATTR_WRITETHRU    XSHAL_XT2000_CACHEATTR_WRITETHRU
-#define XTBOARD_CACHEATTR_BYPASS       XSHAL_XT2000_CACHEATTR_BYPASS
-#define XTBOARD_CACHEATTR_DEFAULT      XSHAL_XT2000_CACHEATTR_DEFAULT
-
-#define XTBOARD_BUSINT_PIPE_REGIONS    XSHAL_XT2000_PIPE_REGIONS
-#define XTBOARD_BUSINT_SDRAM_REGIONS   XSHAL_XT2000_SDRAM_REGIONS
-
-
-
-/*
- *  BusLogic (FPGA) registers.
- *  All these registers are normally accessed using 32-bit loads/stores.
- */
-
-/*  Register offsets:  */
-#define XT2000_DATECD_OFS      0x00    /* date code (read-only) */
-#define XT2000_STSREG_OFS      0x04    /* status (read-only) */
-#define XT2000_SYSLED_OFS      0x08    /* system LED */
-#define XT2000_WRPROT_OFS      0x0C    /* write protect */
-#define XT2000_SWRST_OFS       0x10    /* software reset */
-#define XT2000_SYSRST_OFS      0x14    /* system (peripherals) reset */
-#define XT2000_IMASK_OFS       0x18    /* interrupt mask */
-#define XT2000_ISTAT_OFS       0x1C    /* interrupt status */
-#define XT2000_V3CFG_OFS       0x20    /* V3 config (V320 PCI) */
-
-/*  Physical register addresses:  */
-#ifdef XT2000_FPGAREGS_PADDR
-#define XT2000_DATECD_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_DATECD_OFS)
-#define XT2000_STSREG_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_STSREG_OFS)
-#define XT2000_SYSLED_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_SYSLED_OFS)
-#define XT2000_WRPROT_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_WRPROT_OFS)
-#define XT2000_SWRST_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_SWRST_OFS)
-#define XT2000_SYSRST_PADDR    (XT2000_FPGAREGS_PADDR+XT2000_SYSRST_OFS)
-#define XT2000_IMASK_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_IMASK_OFS)
-#define XT2000_ISTAT_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_ISTAT_OFS)
-#define XT2000_V3CFG_PADDR     (XT2000_FPGAREGS_PADDR+XT2000_V3CFG_OFS)
-#endif
-
-/*  Virtual register addresses:  */
-#ifdef XT2000_FPGAREGS_VADDR
-#define XT2000_DATECD_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_DATECD_OFS)
-#define XT2000_STSREG_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_STSREG_OFS)
-#define XT2000_SYSLED_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_SYSLED_OFS)
-#define XT2000_WRPROT_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_WRPROT_OFS)
-#define XT2000_SWRST_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_SWRST_OFS)
-#define XT2000_SYSRST_VADDR    (XT2000_FPGAREGS_VADDR+XT2000_SYSRST_OFS)
-#define XT2000_IMASK_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_IMASK_OFS)
-#define XT2000_ISTAT_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_ISTAT_OFS)
-#define XT2000_V3CFG_VADDR     (XT2000_FPGAREGS_VADDR+XT2000_V3CFG_OFS)
-/*  Register access (for C code):  */
-#define XT2000_DATECD_REG      (*(volatile unsigned*) XT2000_DATECD_VADDR)
-#define XT2000_STSREG_REG      (*(volatile unsigned*) XT2000_STSREG_VADDR)
-#define XT2000_SYSLED_REG      (*(volatile unsigned*) XT2000_SYSLED_VADDR)
-#define XT2000_WRPROT_REG      (*(volatile unsigned*) XT2000_WRPROT_VADDR)
-#define XT2000_SWRST_REG       (*(volatile unsigned*) XT2000_SWRST_VADDR)
-#define XT2000_SYSRST_REG      (*(volatile unsigned*) XT2000_SYSRST_VADDR)
-#define XT2000_IMASK_REG       (*(volatile unsigned*) XT2000_IMASK_VADDR)
-#define XT2000_ISTAT_REG       (*(volatile unsigned*) XT2000_ISTAT_VADDR)
-#define XT2000_V3CFG_REG       (*(volatile unsigned*) XT2000_V3CFG_VADDR)
-#endif
-
-/*  DATECD (date code) bit fields:  */
-
-/*  BCD-coded month (01..12):  */
-#define XT2000_DATECD_MONTH_SHIFT      24
-#define XT2000_DATECD_MONTH_BITS       8
-#define XT2000_DATECD_MONTH_MASK       0xFF000000
-/*  BCD-coded day (01..31):  */
-#define XT2000_DATECD_DAY_SHIFT                16
-#define XT2000_DATECD_DAY_BITS         8
-#define XT2000_DATECD_DAY_MASK         0x00FF0000
-/*  BCD-coded year (2001..9999):  */
-#define XT2000_DATECD_YEAR_SHIFT       0
-#define XT2000_DATECD_YEAR_BITS                16
-#define XT2000_DATECD_YEAR_MASK                0x0000FFFF
-
-/*  STSREG (status) bit fields:  */
-
-/*  Switch SW3 setting bit fields (0=off/up, 1=on/down):  */
-#define XT2000_STSREG_SW3_SHIFT                0
-#define XT2000_STSREG_SW3_BITS         4
-#define XT2000_STSREG_SW3_MASK         0x0000000F
-/*  Boot-select bits of switch SW3:  */
-#define XT2000_STSREG_BOOTSEL_SHIFT    0
-#define XT2000_STSREG_BOOTSEL_BITS     2
-#define XT2000_STSREG_BOOTSEL_MASK     0x00000003
-/*  Boot-select values:  */
-#define XT2000_STSREG_BOOTSEL_FLASH    0
-#define XT2000_STSREG_BOOTSEL_EPROM16  1
-#define XT2000_STSREG_BOOTSEL_PROM8    2
-#define XT2000_STSREG_BOOTSEL_ASRAM    3
-/*  User-defined bits of switch SW3:  */
-#define XT2000_STSREG_SW3_2_SHIFT      2
-#define XT2000_STSREG_SW3_2_MASK       0x00000004
-#define XT2000_STSREG_SW3_3_SHIFT      3
-#define XT2000_STSREG_SW3_3_MASK       0x00000008
-
-/*  SYSLED (system LED) bit fields:  */
-
-/*  LED control bit (0=off, 1=on):  */
-#define XT2000_SYSLED_LEDON_SHIFT      0
-#define XT2000_SYSLED_LEDON_MASK       0x00000001
-
-/*  WRPROT (write protect) bit fields (0=writable, 1=write-protected [default]):  */
-
-/*  Flash write protect:  */
-#define XT2000_WRPROT_FLWP_SHIFT       0
-#define XT2000_WRPROT_FLWP_MASK                0x00000001
-/*  Reserved but present write protect bits:  */
-#define XT2000_WRPROT_WRP_SHIFT                1
-#define XT2000_WRPROT_WRP_BITS         7
-#define XT2000_WRPROT_WRP_MASK         0x000000FE
-
-/*  SWRST (software reset; allows s/w to generate power-on equivalent reset):  */
-
-/*  Software reset bits:  */
-#define XT2000_SWRST_SWR_SHIFT         0
-#define XT2000_SWRST_SWR_BITS          16
-#define XT2000_SWRST_SWR_MASK          0x0000FFFF
-/*  Software reset value -- writing this value resets the board:  */
-#define XT2000_SWRST_RESETVALUE                0x0000DEAD
-
-/*  SYSRST (system reset; controls reset of individual peripherals):  */
-
-/*  All-device reset:  */
-#define XT2000_SYSRST_ALL_SHIFT                0
-#define XT2000_SYSRST_ALL_BITS         4
-#define XT2000_SYSRST_ALL_MASK         0x0000000F
-/*  HDSP-2534 LED display reset (1=reset, 0=nothing):  */
-#define XT2000_SYSRST_LED_SHIFT                0
-#define XT2000_SYSRST_LED_MASK         0x00000001
-/*  Sonic DP83934 Ethernet controller reset (1=reset, 0=nothing):  */
-#define XT2000_SYSRST_SONIC_SHIFT      1
-#define XT2000_SYSRST_SONIC_MASK       0x00000002
-/*  DP16552 DUART reset (1=reset, 0=nothing):  */
-#define XT2000_SYSRST_DUART_SHIFT      2
-#define XT2000_SYSRST_DUART_MASK       0x00000004
-/*  V3 V320 PCI bridge controller reset (1=reset, 0=nothing):  */
-#define XT2000_SYSRST_V3_SHIFT         3
-#define XT2000_SYSRST_V3_MASK          0x00000008
-
-/*  IMASK (interrupt mask; 0=disable, 1=enable):  */
-/*  ISTAT (interrupt status; 0=inactive, 1=pending):  */
-
-/*  PCI INTP interrupt:  */
-#define XT2000_INTMUX_PCI_INTP_SHIFT   2
-#define XT2000_INTMUX_PCI_INTP_MASK    0x00000004
-/*  PCI INTS interrupt:  */
-#define XT2000_INTMUX_PCI_INTS_SHIFT   3
-#define XT2000_INTMUX_PCI_INTS_MASK    0x00000008
-/*  PCI INTD interrupt:  */
-#define XT2000_INTMUX_PCI_INTD_SHIFT   4
-#define XT2000_INTMUX_PCI_INTD_MASK    0x00000010
-/*  V320 PCI controller interrupt:  */
-#define XT2000_INTMUX_V3_SHIFT         5
-#define XT2000_INTMUX_V3_MASK          0x00000020
-/*  PCI ENUM interrupt:  */
-#define XT2000_INTMUX_PCI_ENUM_SHIFT   6
-#define XT2000_INTMUX_PCI_ENUM_MASK    0x00000040
-/*  PCI DEG interrupt:  */
-#define XT2000_INTMUX_PCI_DEG_SHIFT    7
-#define XT2000_INTMUX_PCI_DEG_MASK     0x00000080
-
-/*  V3CFG (V3 config, V320 PCI controller):  */
-
-/*  V3 address control (0=pass-thru, 1=V3 address bits 31:28 set to 4'b0001 [default]):  */
-#define XT2000_V3CFG_V3ADC_SHIFT       0
-#define XT2000_V3CFG_V3ADC_MASK                0x00000001
-
-/* I2C Devices */
-
-#define        XT2000_I2C_RTC_ID               0x68
-#define        XT2000_I2C_NVRAM0_ID            0x56    /* 1st 256 byte block */
-#define        XT2000_I2C_NVRAM1_ID            0x57    /* 2nd 256 byte block */
-
-/*  NVRAM Board Info structure:  */
-
-#define XT2000_NVRAM_SIZE              512
-
-#define XT2000_NVRAM_BINFO_START       0x100
-#define XT2000_NVRAM_BINFO_SIZE                0x20
-#define XT2000_NVRAM_BINFO_VERSION     0x10    /* version 1.0 */
-#if 0
-#define XT2000_NVRAM_BINFO_VERSION_OFFSET      0x00
-#define XT2000_NVRAM_BINFO_VERSION_SIZE                        0x1
-#define XT2000_NVRAM_BINFO_ETH_ADDR_OFFSET     0x02
-#define XT2000_NVRAM_BINFO_ETH_ADDR_SIZE               0x6
-#define XT2000_NVRAM_BINFO_SN_OFFSET           0x10
-#define XT2000_NVRAM_BINFO_SN_SIZE                     0xE
-#define        XT2000_NVRAM_BINFO_CRC_OFFSET           0x1E
-#define        XT2000_NVRAM_BINFO_CRC_SIZE                     0x2
-#endif /*0*/
-
-#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
-typedef struct xt2000_nvram_binfo {
-    unsigned char      version;
-    unsigned char      reserved1;
-    unsigned char      eth_addr[6];
-    unsigned char      reserved8[8];
-    unsigned char      serialno[14];
-    unsigned char      crc[2];         /* 16-bit CRC */
-} xt2000_nvram_binfo;
-#endif /*!__ASSEMBLY__ && !_NOCLANGUAGE*/
-
-
-#endif /*_INC_XT2000_H_*/
-
diff --git a/include/asm-xtensa/xtensa/xtboard.h b/include/asm-xtensa/xtensa/xtboard.h
deleted file mode 100644 (file)
index 22469c1..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef _xtboard_h_included_
-#define _xtboard_h_included_
-
-/*
- * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
- *
- *  xtboard.h  --  Routines for getting useful information from the board.
- *
- * 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.
- *
- * Copyright (C) 2002 Tensilica Inc.
- */
-
-
-#include <xtensa/xt2000.h>
-
-#define        XTBOARD_RTC_ERROR       -1
-#define        XTBOARD_RTC_STOPPED     -2
-
-
-/*  xt2000-i2cdev.c:  */
-typedef void XtboardDelayFunc( unsigned );
-extern XtboardDelayFunc* xtboard_set_nsdelay_func( XtboardDelayFunc *delay_fn );
-extern int xtboard_i2c_read (unsigned id, unsigned char *buf, unsigned addr, unsigned size);
-extern int xtboard_i2c_write(unsigned id, unsigned char *buf, unsigned addr, unsigned size);
-extern int xtboard_i2c_wait_nvram_ack(unsigned id, unsigned swtimer);
-
-/*  xtboard.c:  */
-extern int xtboard_nvram_read (unsigned addr, unsigned len, unsigned char *buf);
-extern int xtboard_nvram_write(unsigned addr, unsigned len, unsigned char *buf);
-extern int xtboard_nvram_binfo_read (xt2000_nvram_binfo *buf);
-extern int xtboard_nvram_binfo_write(xt2000_nvram_binfo *buf);
-extern int xtboard_nvram_binfo_valid(xt2000_nvram_binfo *buf);
-extern int xtboard_ethermac_get(unsigned char *buf);
-extern int xtboard_ethermac_set(unsigned char *buf);
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_rtc_time
-/
-/ Description:  Get time stored in real-time clock.
-/
-/ Returns: time in seconds stored in real-time clock.
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_get_rtc_time(void);
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_set_rtc_time
-/
-/ Description:  Set time stored in real-time clock.
-/
-/ Parameters:  time -- time in seconds to store to real-time clock
-/
-/ Returns: 0 on success, xtboard_i2c_write() error code otherwise.
-/-**----------------------------------------------------------------------------*/
-
-extern int xtboard_set_rtc_time(unsigned time);
-
-
-/*  xtfreq.c:  */
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_measure_sys_clk
-/
-/ Description:  Get frequency of system clock.
-/
-/ Parameters:  none
-/
-/ Returns: frequency of system clock.
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_measure_sys_clk(void);
-
-
-#if 0  /* old stuff from xtboard.c: */
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_nvram valid
-/
-/ Description:  Determines if data in NVRAM is valid.
-/
-/ Parameters:  delay -- 10us delay function
-/
-/ Returns: 1 if NVRAM is valid, 0 otherwise
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_nvram_valid(void (*delay)( void ));
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_nvram_contents
-/
-/ Description:  Returns contents of NVRAM.
-/
-/ Parameters:  buf -- buffer to NVRAM contents.
-/              delay -- 10us delay function
-/
-/ Returns: 1 if NVRAM is valid, 0 otherwise
-/-**----------------------------------------------------------------------------*/
-
-extern unsigned xtboard_get_nvram_contents(unsigned char *buf, void (*delay)( void ));
-
-/*+*----------------------------------------------------------------------------
-/ Function: xtboard_get_ether_addr
-/
-/ Description:  Returns ethernet address of board.
-/
-/ Parameters:  buf -- buffer to store ethernet address
-/              delay -- 10us delay function
-/
-/ Returns: nothing.
-/-**----------------------------------------------------------------------------*/
-
-extern void xtboard_get_ether_addr(unsigned char *buf, void (*delay)( void ));
-
-#endif /*0*/
-
-
-#endif /*_xtboard_h_included_*/
-
index e618b25b5addc94d65e8926aa9161e6ed24e6a05..a1b04d8a1d01ecf2e64a2334c9c52cda3cc3fd6a 100644 (file)
@@ -61,7 +61,6 @@ header-y += fd.h
 header-y += fdreg.h
 header-y += fib_rules.h
 header-y += fuse.h
-header-y += futex.h
 header-y += genetlink.h
 header-y += gen_stats.h
 header-y += gigaset_dev.h
@@ -203,6 +202,7 @@ unifdef-y += fb.h
 unifdef-y += fcntl.h
 unifdef-y += filter.h
 unifdef-y += flat.h
+unifdef-y += futex.h
 unifdef-y += fs.h
 unifdef-y += gameport.h
 unifdef-y += generic_serial.h
index e1c7286165ffa35c1a47e91b5b0abe56e99091ea..ea330d7b46c089f28f1b4c4f24e81af99b09150b 100644 (file)
@@ -342,7 +342,6 @@ typedef void (unplug_fn) (request_queue_t *);
 
 struct bio_vec;
 typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
-typedef void (activity_fn) (void *data, int rw);
 typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
 typedef void (prepare_flush_fn) (request_queue_t *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
@@ -384,7 +383,6 @@ struct request_queue
        prep_rq_fn              *prep_rq_fn;
        unplug_fn               *unplug_fn;
        merge_bvec_fn           *merge_bvec_fn;
-       activity_fn             *activity_fn;
        issue_flush_fn          *issue_flush_fn;
        prepare_flush_fn        *prepare_flush_fn;
        softirq_done_fn         *softirq_done_fn;
@@ -411,8 +409,6 @@ struct request_queue
         */
        void                    *queuedata;
 
-       void                    *activity_data;
-
        /*
         * queue needs bounce pages for pages above this limit
         */
@@ -677,7 +673,6 @@ extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(request_queue_t *q);
 extern void blk_run_queue(request_queue_t *);
 extern void blk_start_queueing(request_queue_t *);
-extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
 extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long);
 extern int blk_rq_unmap_user(struct request *);
 extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t);
index d852024ed095fb4158be00abeb834df845f52a3f..1622d23a8dc3e9d7390e6642ee0d9f317aea6492 100644 (file)
@@ -159,7 +159,7 @@ static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles)
  * Unless you're the timekeeping code, you should not be using this!
  */
 static inline void clocksource_calculate_interval(struct clocksource *c,
-                                               unsigned long length_nsec)
+                                                 unsigned long length_nsec)
 {
        u64 tmp;
 
index ed6cc8962d87b9e8c50df5059b6c475450cf1a80..1cb054bd93f2805fcb1ee88e966d75b3e498423e 100644 (file)
@@ -176,20 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
- enum {
-       DCCPF_RESERVED = 0,
-       DCCPF_CCID = 1,
+enum {
+       DCCPF_RESERVED = 0,
+       DCCPF_CCID = 1,
        DCCPF_SHORT_SEQNOS = 2,         /* XXX: not yet implemented */
-       DCCPF_SEQUENCE_WINDOW = 3,
+       DCCPF_SEQUENCE_WINDOW = 3,
        DCCPF_ECN_INCAPABLE = 4,        /* XXX: not yet implemented */
-       DCCPF_ACK_RATIO = 5,
-       DCCPF_SEND_ACK_VECTOR = 6,
-       DCCPF_SEND_NDP_COUNT = 7,
+       DCCPF_ACK_RATIO = 5,
+       DCCPF_SEND_ACK_VECTOR = 6,
+       DCCPF_SEND_NDP_COUNT = 7,
        DCCPF_MIN_CSUM_COVER = 8,
        DCCPF_DATA_CHECKSUM = 9,        /* XXX: not yet implemented */
-       /* 10-127 reserved */
-       DCCPF_MIN_CCID_SPECIFIC = 128,
-       DCCPF_MAX_CCID_SPECIFIC = 255,
+       /* 10-127 reserved */
+       DCCPF_MIN_CCID_SPECIFIC = 128,
+       DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
 /* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
@@ -427,7 +427,7 @@ struct dccp_service_list {
 };
 
 #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
-#define DCCP_SERVICE_CODE_IS_ABSENT             0
+#define DCCP_SERVICE_CODE_IS_ABSENT            0
 
 static inline int dccp_list_has_service(const struct dccp_service_list *sl,
                                        const __be32 service)
@@ -436,7 +436,7 @@ static inline int dccp_list_has_service(const struct dccp_service_list *sl,
                u32 i = sl->dccpsl_nr;
                while (i--)
                        if (sl->dccpsl_list[i] == service)
-                               return 1; 
+                               return 1;
        }
        return 0;
 }
@@ -511,7 +511,7 @@ struct dccp_sock {
        __u8                            dccps_hc_tx_insert_options:1;
        struct timer_list               dccps_xmit_timer;
 };
+
 static inline struct dccp_sock *dccp_sk(const struct sock *sk)
 {
        return (struct dccp_sock *)sk;
index 6e77b9177f9e86ffd552fd9dcae491bc6715a6b1..edca361f2ab4c7babd090e42b5a43ffc64eb54ef 100644 (file)
@@ -26,19 +26,12 @@ struct embedded_fd_set {
        unsigned long fds_bits[1];
 };
 
-/*
- * More than this number of fds: we use a separately allocated fd_set
- */
-#define EMBEDDED_FD_SET_SIZE (BITS_PER_BYTE * sizeof(struct embedded_fd_set))
-
 struct fdtable {
        unsigned int max_fds;
-       int max_fdset;
        struct file ** fd;      /* current fd array */
        fd_set *close_on_exec;
        fd_set *open_fds;
        struct rcu_head rcu;
-       struct files_struct *free_files;
        struct fdtable *next;
 };
 
@@ -83,14 +76,8 @@ extern int get_unused_fd(void);
 extern void FASTCALL(put_unused_fd(unsigned int fd));
 struct kmem_cache;
 
-extern struct file ** alloc_fd_array(int);
-extern void free_fd_array(struct file **, int);
-
-extern fd_set *alloc_fdset(int);
-extern void free_fdset(fd_set *, int);
-
 extern int expand_files(struct files_struct *, int nr);
-extern void free_fdtable(struct fdtable *fdt);
+extern void free_fdtable_rcu(struct rcu_head *rcu);
 extern void __init files_defer_init(void);
 
 static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
index 6e05e3e7ce396560f10d902c311f58c6457cabe0..393063096134d505cedf33fb216ce943bae23b6e 100644 (file)
@@ -1,5 +1,7 @@
 /* Freezer declarations */
 
+#include <linux/sched.h>
+
 #ifdef CONFIG_PM
 /*
  * Check if a process has been frozen
index 3da29e2d524a57a8bc5fe80cc9942da561c1f32b..abb64c437f6fd92b447deb18768549d7cbb45ddc 100644 (file)
@@ -19,6 +19,7 @@
 #define _FSL_DEVICE_H_
 
 #include <linux/types.h>
+#include <linux/phy.h>
 
 /*
  * Some conventions on how we handle peripherals on Freescale chips
index d097b5b72bc653b0a3a35c17d22c66edc6839cb3..3f153b4e156c4e9be16c70570276c02d3aecba8c 100644 (file)
@@ -93,6 +93,7 @@ struct robust_list_head {
  */
 #define ROBUST_LIST_LIMIT      2048
 
+#ifdef __KERNEL__
 long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
              u32 __user *uaddr2, u32 val2, u32 val3);
 
@@ -110,6 +111,7 @@ static inline void exit_pi_state_list(struct task_struct *curr)
 {
 }
 #endif
+#endif /* __KERNEL__ */
 
 #define FUTEX_OP_SET           0       /* *(int *)UADDR2 = OPARG; */
 #define FUTEX_OP_ADD           1       /* *(int *)UADDR2 += OPARG; */
index 5b97f1cce7a53257bb296181fdcc2ab7c26a31d7..7ae3c3326643a1d19ad1436192e27a554aa172e4 100644 (file)
 #define I2C_DRIVERID_ASB100 1043
 #define I2C_DRIVERID_FSCHER 1046
 #define I2C_DRIVERID_W83L785TS 1047
+#define I2C_DRIVERID_OV7670 1048       /* Omnivision 7670 camera */
 
 /*
  * ---- Adapter types ----------------------------------------------------
 #define I2C_HW_SMBUS_OV518     0x04000f /* OV518(+) USB 1.1 webcam ICs */
 #define I2C_HW_SMBUS_OV519     0x040010 /* OV519 USB 1.1 webcam IC */
 #define I2C_HW_SMBUS_OVFX2     0x040011 /* Cypress/OmniVision FX2 webcam */
+#define I2C_HW_SMBUS_CAFE      0x040012 /* Marvell 88ALP01 "CAFE" cam  */
 
 /* --- ISA pseudo-adapter                                              */
 #define I2C_HW_ISA             0x050000
index 9c2050293f17c81727d70ffc44eea24a95e7e9f1..e26a03981a94a0abc9f4ea59e68ae3cf27967238 100644 (file)
@@ -796,6 +796,7 @@ typedef struct hwif_s {
        unsigned        sg_mapped  : 1; /* sg_table and sg_nents are ready */
        unsigned        no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
        unsigned        err_stops_fifo : 1; /* 1=data FIFO is cleared by an error */
+       unsigned        atapi_irq_bogon : 1; /* Generates spurious DMA interrupts in PIO mode */
 
        struct device   gendev;
        struct completion gendev_rel_comp; /* To deal with device release() */
@@ -803,8 +804,6 @@ typedef struct hwif_s {
        void            *hwif_data;     /* extra hwif data */
 
        unsigned dma;
-
-       void (*led_act)(void *data, int rw);
 } ____cacheline_internodealigned_in_smp ide_hwif_t;
 
 /*
index 5eb5d24b7680fea25a97b44df24424e60342658b..5a593a1dec1efd7f53ab6ac58349db9b996157d2 100644 (file)
@@ -111,6 +111,7 @@ extern void setup_arch(char **);
 #define subsys_initcall_sync(fn)       __define_initcall("4s",fn,4s)
 #define fs_initcall(fn)                        __define_initcall("5",fn,5)
 #define fs_initcall_sync(fn)           __define_initcall("5s",fn,5s)
+#define rootfs_initcall(fn)            __define_initcall("rootfs",fn,rootfs)
 #define device_initcall(fn)            __define_initcall("6",fn,6)
 #define device_initcall_sync(fn)       __define_initcall("6s",fn,6s)
 #define late_initcall(fn)              __define_initcall("7",fn,7)
index 7272ff9ee77c58617c0897ddc222018ae89b3d41..b5315150199e9528bbfa1b5fcfe64b669b199058 100644 (file)
 #define INIT_FDTABLE \
 {                                                      \
        .max_fds        = NR_OPEN_DEFAULT,              \
-       .max_fdset      = EMBEDDED_FD_SET_SIZE,         \
        .fd             = &init_files.fd_array[0],      \
        .close_on_exec  = (fd_set *)&init_files.close_on_exec_init, \
        .open_fds       = (fd_set *)&init_files.open_fds_init,  \
        .rcu            = RCU_HEAD_INIT,                \
-       .free_files     = NULL,                         \
        .next           = NULL,                         \
 }
 
index de7593f4e895b4bfaa77c7e22051e372a5b5a48c..e36e86c869fb4e6576e3c67fd1febd0d16ba1ea2 100644 (file)
@@ -231,7 +231,8 @@ enum
        NET_TX_SOFTIRQ,
        NET_RX_SOFTIRQ,
        BLOCK_SOFTIRQ,
-       TASKLET_SOFTIRQ
+       TASKLET_SOFTIRQ,
+       SCHED_SOFTIRQ,
 };
 
 /* softirq mask and active fields moved to irq_cpustat_t in
index e8bfac34d2ba1cdd6192b5c270ef9d41159df883..b0c4a05a4b0caae1fa509f767d3246ed9a484351 100644 (file)
@@ -17,8 +17,6 @@
 #include <asm/byteorder.h>
 #include <asm/bug.h>
 
-extern const char linux_banner[];
-
 #define INT_MAX                ((int)(~0U>>1))
 #define INT_MIN                (-INT_MAX - 1)
 #define UINT_MAX       (~0U)
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
new file mode 100644 (file)
index 0000000..5bb2c3c
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef __LINUX_KVM_H
+#define __LINUX_KVM_H
+
+/*
+ * Userspace interface for /dev/kvm - kernel based virtual machine
+ *
+ * Note: this interface is considered experimental and may change without
+ *       notice.
+ */
+
+#include <asm/types.h>
+#include <linux/ioctl.h>
+
+/*
+ * Architectural interrupt line count, and the size of the bitmap needed
+ * to hold them.
+ */
+#define KVM_NR_INTERRUPTS 256
+#define KVM_IRQ_BITMAP_SIZE_BYTES    ((KVM_NR_INTERRUPTS + 7) / 8)
+#define KVM_IRQ_BITMAP_SIZE(type)    (KVM_IRQ_BITMAP_SIZE_BYTES / sizeof(type))
+
+
+/* for KVM_CREATE_MEMORY_REGION */
+struct kvm_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+};
+
+/* for kvm_memory_region::flags */
+#define KVM_MEM_LOG_DIRTY_PAGES  1UL
+
+
+#define KVM_EXIT_TYPE_FAIL_ENTRY 1
+#define KVM_EXIT_TYPE_VM_EXIT    2
+
+enum kvm_exit_reason {
+       KVM_EXIT_UNKNOWN          = 0,
+       KVM_EXIT_EXCEPTION        = 1,
+       KVM_EXIT_IO               = 2,
+       KVM_EXIT_CPUID            = 3,
+       KVM_EXIT_DEBUG            = 4,
+       KVM_EXIT_HLT              = 5,
+       KVM_EXIT_MMIO             = 6,
+};
+
+/* for KVM_RUN */
+struct kvm_run {
+       /* in */
+       __u32 vcpu;
+       __u32 emulated;  /* skip current instruction */
+       __u32 mmio_completed; /* mmio request completed */
+
+       /* out */
+       __u32 exit_type;
+       __u32 exit_reason;
+       __u32 instruction_length;
+       union {
+               /* KVM_EXIT_UNKNOWN */
+               struct {
+                       __u32 hardware_exit_reason;
+               } hw;
+               /* KVM_EXIT_EXCEPTION */
+               struct {
+                       __u32 exception;
+                       __u32 error_code;
+               } ex;
+               /* KVM_EXIT_IO */
+               struct {
+#define KVM_EXIT_IO_IN  0
+#define KVM_EXIT_IO_OUT 1
+                       __u8 direction;
+                       __u8 size; /* bytes */
+                       __u8 string;
+                       __u8 string_down;
+                       __u8 rep;
+                       __u8 pad;
+                       __u16 port;
+                       __u64 count;
+                       union {
+                               __u64 address;
+                               __u32 value;
+                       };
+               } io;
+               struct {
+               } debug;
+               /* KVM_EXIT_MMIO */
+               struct {
+                       __u64 phys_addr;
+                       __u8  data[8];
+                       __u32 len;
+                       __u8  is_write;
+               } mmio;
+       };
+};
+
+/* for KVM_GET_REGS and KVM_SET_REGS */
+struct kvm_regs {
+       /* in */
+       __u32 vcpu;
+       __u32 padding;
+
+       /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+       __u64 rax, rbx, rcx, rdx;
+       __u64 rsi, rdi, rsp, rbp;
+       __u64 r8,  r9,  r10, r11;
+       __u64 r12, r13, r14, r15;
+       __u64 rip, rflags;
+};
+
+struct kvm_segment {
+       __u64 base;
+       __u32 limit;
+       __u16 selector;
+       __u8  type;
+       __u8  present, dpl, db, s, l, g, avl;
+       __u8  unusable;
+       __u8  padding;
+};
+
+struct kvm_dtable {
+       __u64 base;
+       __u16 limit;
+       __u16 padding[3];
+};
+
+/* for KVM_GET_SREGS and KVM_SET_SREGS */
+struct kvm_sregs {
+       /* in */
+       __u32 vcpu;
+       __u32 padding;
+
+       /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
+       struct kvm_segment cs, ds, es, fs, gs, ss;
+       struct kvm_segment tr, ldt;
+       struct kvm_dtable gdt, idt;
+       __u64 cr0, cr2, cr3, cr4, cr8;
+       __u64 efer;
+       __u64 apic_base;
+       __u64 interrupt_bitmap[KVM_IRQ_BITMAP_SIZE(__u64)];
+};
+
+struct kvm_msr_entry {
+       __u32 index;
+       __u32 reserved;
+       __u64 data;
+};
+
+/* for KVM_GET_MSRS and KVM_SET_MSRS */
+struct kvm_msrs {
+       __u32 vcpu;
+       __u32 nmsrs; /* number of msrs in entries */
+
+       struct kvm_msr_entry entries[0];
+};
+
+/* for KVM_GET_MSR_INDEX_LIST */
+struct kvm_msr_list {
+       __u32 nmsrs; /* number of msrs in entries */
+       __u32 indices[0];
+};
+
+/* for KVM_TRANSLATE */
+struct kvm_translation {
+       /* in */
+       __u64 linear_address;
+       __u32 vcpu;
+       __u32 padding;
+
+       /* out */
+       __u64 physical_address;
+       __u8  valid;
+       __u8  writeable;
+       __u8  usermode;
+};
+
+/* for KVM_INTERRUPT */
+struct kvm_interrupt {
+       /* in */
+       __u32 vcpu;
+       __u32 irq;
+};
+
+struct kvm_breakpoint {
+       __u32 enabled;
+       __u32 padding;
+       __u64 address;
+};
+
+/* for KVM_DEBUG_GUEST */
+struct kvm_debug_guest {
+       /* int */
+       __u32 vcpu;
+       __u32 enabled;
+       struct kvm_breakpoint breakpoints[4];
+       __u32 singlestep;
+};
+
+/* for KVM_GET_DIRTY_LOG */
+struct kvm_dirty_log {
+       __u32 slot;
+       __u32 padding;
+       union {
+               void __user *dirty_bitmap; /* one bit per page */
+               __u64 padding;
+       };
+};
+
+#define KVMIO 0xAE
+
+#define KVM_RUN                   _IOWR(KVMIO, 2, struct kvm_run)
+#define KVM_GET_REGS              _IOWR(KVMIO, 3, struct kvm_regs)
+#define KVM_SET_REGS              _IOW(KVMIO, 4, struct kvm_regs)
+#define KVM_GET_SREGS             _IOWR(KVMIO, 5, struct kvm_sregs)
+#define KVM_SET_SREGS             _IOW(KVMIO, 6, struct kvm_sregs)
+#define KVM_TRANSLATE             _IOWR(KVMIO, 7, struct kvm_translation)
+#define KVM_INTERRUPT             _IOW(KVMIO, 8, struct kvm_interrupt)
+#define KVM_DEBUG_GUEST           _IOW(KVMIO, 9, struct kvm_debug_guest)
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 10, struct kvm_memory_region)
+#define KVM_CREATE_VCPU           _IOW(KVMIO, 11, int /* vcpu_slot */)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO, 12, struct kvm_dirty_log)
+#define KVM_GET_MSRS              _IOWR(KVMIO, 13, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOWR(KVMIO, 14, struct kvm_msrs)
+#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 15, struct kvm_msr_list)
+
+#endif
index 03636d7918fef80b565b0e1141247be35c79bd88..d8286db60b96572153a9f22ec94f0b91ef7ff41a 100644 (file)
@@ -227,7 +227,10 @@ struct raid5_private_data {
        struct list_head        handle_list; /* stripes needing handling */
        struct list_head        delayed_list; /* stripes that have plugged requests */
        struct list_head        bitmap_list; /* stripes delaying awaiting bitmap update */
+       struct bio              *retry_read_aligned; /* currently retrying aligned bios   */
+       struct bio              *retry_read_aligned_list; /* aligned bios retry list  */
        atomic_t                preread_active_stripes; /* stripes with scheduled io */
+       atomic_t                active_aligned_reads;
 
        atomic_t                reshape_stripes; /* stripes with pending writes for reshape */
        /* unfortunately we need two cache names as we temporarily have
index 09ff4c3e2713e3184eea072787f96c6fba918def..5e22d4510d11107eb67ffdb3c82f378ef1f9eccc 100644 (file)
@@ -106,6 +106,7 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
 extern int rtc_valid_tm(struct rtc_time *tm);
 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm);
 
 #include <linux/device.h>
 #include <linux/seq_file.h>
index ad9c46071ff8bf43195f104ab842b27698f8f5e7..ea92e5c890894694533ea42a0d95e2148ff301c9 100644 (file)
@@ -82,6 +82,7 @@ struct sched_param {
 #include <linux/resource.h>
 #include <linux/timer.h>
 #include <linux/hrtimer.h>
+#include <linux/task_io_accounting.h>
 
 #include <asm/processor.h>
 
@@ -647,6 +648,7 @@ enum idle_type
 #define SD_SHARE_CPUPOWER      128     /* Domain members share cpu power */
 #define SD_POWERSAVINGS_BALANCE        256     /* Balance for power savings */
 #define SD_SHARE_PKG_RESOURCES 512     /* Domain members share cpu pkg resources */
+#define SD_SERIALIZE           1024    /* Only a single load balancing instance */
 
 #define BALANCE_FOR_MC_POWER   \
        (sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0)
@@ -1013,6 +1015,7 @@ struct task_struct {
        wait_queue_t *io_wait;
 /* i/o counters(bytes read/written, #syscalls */
        u64 rchar, wchar, syscr, syscw;
+       struct task_io_accounting ioac;
 #if defined(CONFIG_TASK_XACCT)
        u64 acct_rss_mem1;      /* accumulated rss usage */
        u64 acct_vm_mem1;       /* accumulated virtual memory usage */
index 46000936f8f1d5f39e92aa1e260518475b567e1a..6b0648cfdffcf869ee59784db66e81ae8991a382 100644 (file)
@@ -44,8 +44,11 @@ typedef struct {
 #define SEQLOCK_UNLOCKED \
                 __SEQLOCK_UNLOCKED(old_style_seqlock_init)
 
-#define seqlock_init(x) \
-               do { *(x) = (seqlock_t) __SEQLOCK_UNLOCKED(x); } while (0)
+#define seqlock_init(x)                                        \
+       do {                                            \
+               (x)->sequence = 0;                      \
+               spin_lock_init(&(x)->lock);             \
+       } while (0)
 
 #define DEFINE_SEQLOCK(x) \
                seqlock_t x = __SEQLOCK_UNLOCKED(x)
index 94316a98e0d006b064a96734e1e1d9302e6225e5..6d8846e7be6da62b65422842efc20ff5b9205aa1 100644 (file)
@@ -918,8 +918,7 @@ typedef struct ctl_table ctl_table;
 
 typedef int ctl_handler (ctl_table *table, int __user *name, int nlen,
                         void __user *oldval, size_t __user *oldlenp,
-                        void __user *newval, size_t newlen, 
-                        void **context);
+                        void __user *newval, size_t newlen);
 
 typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
                          void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -950,7 +949,7 @@ extern int do_sysctl (int __user *name, int nlen,
 extern int do_sysctl_strategy (ctl_table *table, 
                               int __user *name, int nlen,
                               void __user *oldval, size_t __user *oldlenp,
-                              void __user *newval, size_t newlen, void ** context);
+                              void __user *newval, size_t newlen);
 
 extern ctl_handler sysctl_string;
 extern ctl_handler sysctl_intvec;
diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h
new file mode 100644 (file)
index 0000000..44d00e9
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * task_io_accounting: a structure which is used for recording a single task's
+ * IO statistics.
+ *
+ * Don't include this header file directly - it is designed to be dragged in via
+ * sched.h.
+ *
+ * Blame akpm@osdl.org for all this.
+ */
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+struct task_io_accounting {
+       /*
+        * The number of bytes which this task has caused to be read from
+        * storage.
+        */
+       u64 read_bytes;
+
+       /*
+        * The number of bytes which this task has caused, or shall cause to be
+        * written to disk.
+        */
+       u64 write_bytes;
+
+       /*
+        * A task can cause "negative" IO too.  If this task truncates some
+        * dirty pagecache, some IO which another task has been accounted for
+        * (in its write_bytes) will not be happening.  We _could_ just
+        * subtract that from the truncating task's write_bytes, but there is
+        * information loss in doing that.
+        */
+       u64 cancelled_write_bytes;
+};
+#else
+struct task_io_accounting {
+};
+#endif
diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h
new file mode 100644 (file)
index 0000000..df2a319
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Task I/O accounting operations
+ */
+#ifndef __TASK_IO_ACCOUNTING_OPS_INCLUDED
+#define __TASK_IO_ACCOUNTING_OPS_INCLUDED
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static inline void task_io_account_read(size_t bytes)
+{
+       current->ioac.read_bytes += bytes;
+}
+
+static inline void task_io_account_write(size_t bytes)
+{
+       current->ioac.write_bytes += bytes;
+}
+
+static inline void task_io_account_cancelled_write(size_t bytes)
+{
+       current->ioac.cancelled_write_bytes += bytes;
+}
+
+static inline void task_io_accounting_init(struct task_struct *tsk)
+{
+       memset(&tsk->ioac, 0, sizeof(tsk->ioac));
+}
+
+#else
+
+static inline void task_io_account_read(size_t bytes)
+{
+}
+
+static inline void task_io_account_write(size_t bytes)
+{
+}
+
+static inline void task_io_account_cancelled_write(size_t bytes)
+{
+}
+
+static inline void task_io_accounting_init(struct task_struct *tsk)
+{
+}
+
+#endif         /* CONFIG_TASK_IO_ACCOUNTING */
+#endif         /* __TASK_IO_ACCOUNTING_OPS_INCLUDED */
index 45248806ae9c5916a416102d9bd1a8c9b54a03a2..3fced4798255101b1ec8f19aeb5905cb449bc8d2 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 
-#define TASKSTATS_VERSION      2
+#define TASKSTATS_VERSION      3
 #define TS_COMM_LEN            32      /* should be >= TASK_COMM_LEN
                                         * in linux/sched.h */
 
@@ -115,31 +115,37 @@ struct taskstats {
        __u64   ac_majflt;              /* Major Page Fault Count */
        /* Basic Accounting Fields end */
 
-       /* Extended accounting fields start */
+       /* Extended accounting fields start */
        /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
         * The current rss usage is added to this counter every time
         * a tick is charged to a task's system time. So, at the end we
         * will have memory usage multiplied by system time. Thus an
         * average usage per system time unit can be calculated.
         */
-       __u64   coremem;                /* accumulated RSS usage in MB-usec */
+       __u64   coremem;                /* accumulated RSS usage in MB-usec */
        /* Accumulated virtual memory usage in duration of a task.
         * Same as acct_rss_mem1 above except that we keep track of VM usage.
         */
-       __u64   virtmem;                /* accumulated VM  usage in MB-usec */
+       __u64   virtmem;                /* accumulated VM  usage in MB-usec */
 
        /* High watermark of RSS and virtual memory usage in duration of
         * a task, in KBytes.
         */
-       __u64   hiwater_rss;            /* High-watermark of RSS usage, in KB */
-       __u64   hiwater_vm;             /* High-water VM usage, in KB */
+       __u64   hiwater_rss;            /* High-watermark of RSS usage, in KB */
+       __u64   hiwater_vm;             /* High-water VM usage, in KB */
 
        /* The following four fields are I/O statistics of a task. */
-       __u64   read_char;              /* bytes read */
-       __u64   write_char;             /* bytes written */
-       __u64   read_syscalls;          /* read syscalls */
-       __u64   write_syscalls;         /* write syscalls */
-       /* Extended accounting fields end */
+       __u64   read_char;              /* bytes read */
+       __u64   write_char;             /* bytes written */
+       __u64   read_syscalls;          /* read syscalls */
+       __u64   write_syscalls;         /* write syscalls */
+       /* Extended accounting fields end */
+
+#define TASKSTATS_HAS_IO_ACCOUNTING
+       /* Per-task storage I/O accounting starts */
+       __u64   read_bytes;             /* bytes of read I/O */
+       __u64   write_bytes;            /* bytes of write I/O */
+       __u64   cancelled_write_bytes;  /* bytes of cancelled write I/O */
 };
 
 
index 31a9b25276fe02d5d951f243b863c735cc8fd3e4..8a8462b4a4ddcdf18dfc4fef04f135f23b02f786 100644 (file)
@@ -37,10 +37,14 @@ struct tfrc_rx_info {
  *     @tfrctx_p:      current loss event rate (5.4)
  *     @tfrctx_rto:    estimate of RTO, equals 4*RTT (4.3)
  *     @tfrctx_ipi:    inter-packet interval (4.6)
+ *
+ *  Note: X and X_recv are both maintained in units of 64 * bytes/second. This
+ *        enables a finer resolution of sending rates and avoids problems with
+ *        integer arithmetic; u32 is not sufficient as scaling consumes 6 bits.
  */
 struct tfrc_tx_info {
-       __u32 tfrctx_x;
-       __u32 tfrctx_x_recv;
+       __u64 tfrctx_x;
+       __u64 tfrctx_x_recv;
        __u32 tfrctx_x_calc;
        __u32 tfrctx_rtt;
        __u32 tfrctx_p;
index c982304dbafd4f30faf9764c377b442894f20282..eeef6643d4c6144df0fd7f54cf4388b22f4f316a 100644 (file)
@@ -98,4 +98,10 @@ extern void run_local_timers(void);
 struct hrtimer;
 extern int it_real_fn(struct hrtimer *);
 
+unsigned long __round_jiffies(unsigned long j, int cpu);
+unsigned long __round_jiffies_relative(unsigned long j, int cpu);
+unsigned long round_jiffies(unsigned long j);
+unsigned long round_jiffies_relative(unsigned long j);
+
+
 #endif
index da508d1998e413714ee788a4602d2a6478dba96d..6c5a6e6e813bcb4529a5ef84e23dc5c5370c2950 100644 (file)
@@ -93,7 +93,7 @@
        .groups                 = NULL,                 \
        .min_interval           = 1,                    \
        .max_interval           = 2,                    \
-       .busy_factor            = 8,                    \
+       .busy_factor            = 64,                   \
        .imbalance_pct          = 110,                  \
        .cache_nice_tries       = 0,                    \
        .per_cpu_gain           = 25,                   \
        .wake_idx               = 0, /* unused */       \
        .forkexec_idx           = 0, /* unused */       \
        .per_cpu_gain           = 100,                  \
-       .flags                  = SD_LOAD_BALANCE,      \
+       .flags                  = SD_LOAD_BALANCE       \
+                               | SD_SERIALIZE, \
        .last_balance           = jiffies,              \
        .balance_interval       = 64,                   \
        .nr_balance_failed      = 0,                    \
index df5c4654360d029ba95f222d22b3a74042556944..5cb380a559fd51f379bef2b2c63462737c2ac646 100644 (file)
@@ -244,6 +244,7 @@ struct v4l2_pix_format
 #define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y','Y','U','V') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_HI240   v4l2_fourcc('H','I','2','4') /*  8  8-bit color   */
 #define V4L2_PIX_FMT_HM12    v4l2_fourcc('H','M','1','2') /*  8  YUV 4:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_RGB444  v4l2_fourcc('R','4','4','4') /* 16  xxxxrrrr ggggbbbb */
 
 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
index 8f58406533c64c6b1ae0fb6ebd0343783963dcd8..2b25f5c950068b0ea1be5f1b85d627d169b86098 100644 (file)
@@ -92,6 +92,7 @@ extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
 
 #endif
 
index fee579f10b32ad11cd87bca320a6f9f59eefbb43..796bcf151a3abf3061b9c6fae3eec2ada0f68063 100644 (file)
@@ -42,10 +42,6 @@ extern unsigned int saa7146_debug;
 #define DEB_INT(x)  if (0!=(DEBUG_VARIABLE&0x20)) { DEBUG_PROLOG; printk x; } /* interrupt debug messages */
 #define DEB_CAP(x)  if (0!=(DEBUG_VARIABLE&0x40)) { DEBUG_PROLOG; printk x; } /* capture debug messages */
 
-#define SAA7146_IER_DISABLE(x,y) \
-       saa7146_write(x, IER, saa7146_read(x, IER) & ~(y));
-#define SAA7146_IER_ENABLE(x,y) \
-       saa7146_write(x, IER, saa7146_read(x, IER) | (y));
 #define SAA7146_ISR_CLEAR(x,y) \
        saa7146_write(x, ISR, (y));
 
@@ -441,4 +437,20 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
 #define SAA7146_I2C_BUS_BIT_RATE_80    (0x200)
 #define SAA7146_I2C_BUS_BIT_RATE_60    (0x300)
 
+static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&x->int_slock, flags);
+       saa7146_write(x, IER, saa7146_read(x, IER) & ~y);
+       spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
+static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&x->int_slock, flags);
+       saa7146_write(x, IER, saa7146_read(x, IER) | y);
+       spin_unlock_irqrestore(&x->int_slock, flags);
+}
+
 #endif
index 37dad07a8439434c26127c2c766ceb8b2c03354f..e5ad3fcfe9845d1ba8a37babcd3871461a141f29 100644 (file)
@@ -50,6 +50,10 @@ struct tuner_params {
           sensitivity. If this setting is 1, then set PORT2 to 1 to
           get proper FM reception. */
        unsigned int port2_fm_high_sensitivity:1;
+       /* Some Philips tuners use tda9887 cGainNormal to select the FM radio
+          sensitivity. If this setting is 1, e register will use cGainNormal
+          instead of cGainLow. */
+       unsigned int fm_gain_normal:1;
        /* Most tuners with a tda9887 use QSS mode. Some (cheaper) tuners
           use Intercarrier mode. If this setting is 1, then the tuner
           needs to be set to intercarrier mode. */
index 3116e750132f2e7575e07d2caced3b21bdf34bdb..99acf847365caa81d4bab76a3dcd4e954fc145e0 100644 (file)
@@ -145,6 +145,7 @@ extern int tuner_debug;
 #define TDA9887_DEEMPHASIS_75          (3<<16)
 #define TDA9887_AUTOMUTE               (1<<18)
 #define TDA9887_GATING_18              (1<<19)
+#define TDA9887_GAIN_NORMAL            (1<<20)
 
 #ifdef __KERNEL__
 
index e9fc1a7854970aaccf6eb8252cbd3914c41bdfd9..5660ea24996b42f0634c5fb0a6267131d36fca25 100644 (file)
@@ -3,7 +3,7 @@
 
 struct tveeprom {
        u32 has_radio;
-       u32 has_ir;     /* 0: no IR, 1: IR present, 2: unknown */
+       u32 has_ir;     /* bit 0: IR receiver present, bit 1: IR transmitter (blaster) present. -1 == unknown */
        u32 has_MAC_address; /* 0: no MAC, 1: MAC present, 2: unknown */
 
        u32 tuner_type;
index aecc946980a3a7da00ce0f7b90fbaf70248bf7a1..91b19921f958af283e5fc78521847c5b7785ca3c 100644 (file)
@@ -144,6 +144,9 @@ enum v4l2_chip_ident {
        V4L2_IDENT_CX25841 = 241,
        V4L2_IDENT_CX25842 = 242,
        V4L2_IDENT_CX25843 = 243,
+
+       /* OmniVision sensors - range 250-299 */
+       V4L2_IDENT_OV7670 = 250,
 };
 
 /* audio ioctls */
@@ -251,4 +254,8 @@ struct v4l2_crystal_freq {
    If the frequency is not supported, then -EINVAL is returned. */
 #define VIDIOC_INT_S_CRYSTAL_FREQ      _IOW ('d', 113, struct v4l2_crystal_freq)
 
+/* Initialize the sensor registors to some sort of reasonable
+   default values. */
+#define VIDIOC_INT_INIT                        _IOW ('d', 114, u32)
+
 #endif /* V4L2_COMMON_H_ */
index 6a11d772700ff649e9a1d81b47db9f8622af3594..fb96472a1bd38423c4a3ac0790fb14b78064a28e 100644 (file)
@@ -43,6 +43,7 @@
 
 /*  Video standard functions  */
 extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern char *v4l2_norm_to_name(v4l2_std_id id);
 extern int v4l2_video_std_construct(struct v4l2_standard *vs,
                                    int id, char *name);
 
@@ -81,12 +82,6 @@ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
  *     This version moves redundant code from video device code to
  *     the common handler
  */
-struct v4l2_tvnorm {
-       char          *name;
-       v4l2_std_id   id;
-
-       void          *priv_data;
-};
 
 struct video_device
 {
@@ -104,9 +99,8 @@ struct video_device
        int debug;      /* Activates debug level*/
 
        /* Video standard vars */
-       int tvnormsize; /* Size of tvnorm array */
-       v4l2_std_id current_norm; /* Current tvnorm */
-       struct v4l2_tvnorm *tvnorms;
+       v4l2_std_id tvnorms;            /* Supported tv norms */
+       v4l2_std_id current_norm;       /* Current tvnorm */
 
        /* callbacks */
        void (*release)(struct video_device *vfd);
@@ -211,7 +205,7 @@ struct video_device
                /* Standard handling
                        G_STD and ENUMSTD are handled by videodev.c
                 */
-       int (*vidioc_s_std)    (struct file *file, void *fh, v4l2_std_id a);
+       int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
        int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
 
                /* Input handling */
index e1d116f1192359d2c037d74693200ac374adeb1a..14b72d868f03eeb479cd631f92b5caa2fb9f3216 100644 (file)
@@ -285,6 +285,8 @@ extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
 extern const ax25_address ax25_bcast;
 extern const ax25_address ax25_defaddr;
 extern const ax25_address null_ax25_address;
+extern char *ax2asc(char *buf, const ax25_address *);
+extern void asc2ax(ax25_address *addr, const char *callsign);
 extern int ax25cmp(const ax25_address *, const ax25_address *);
 extern int ax25digicmp(const ax25_digi *, const ax25_digi *);
 extern const unsigned char *ax25_addr_parse(const unsigned char *, int,
index 83cb9ac5554e31e870df16127ece18076487f8a6..053f02b5cb89f1dacb93a553980b34b9897eb27e 100644 (file)
@@ -376,8 +376,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
                         size_t *lenp, loff_t *ppos);
 int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
                                  void __user *oldval, size_t __user *oldlenp,
-                                 void __user *newval, size_t newlen, 
-                                 void **context);
+                                 void __user *newval, size_t newlen);
 #ifdef CONFIG_PROC_FS
 extern int ip_misc_proc_init(void);
 #endif
index 215461f18db183dac777fbf4b9eec2f6ab13055d..c818f87122af1c4046a643a4ab374f5adc5e6ea7 100644 (file)
@@ -368,7 +368,7 @@ static inline void sctp_sysctl_register(void) { return; }
 static inline void sctp_sysctl_unregister(void) { return; }
 static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context) {
+               void __user *newval, size_t newlen) {
        return -ENOSYS;
 }
 #endif
index 14d484606fab9b0bbdff72b318d664fc5d7b73b3..9edf103b3ec39f06ad64c7e57cde219239865313 100644 (file)
@@ -304,6 +304,15 @@ config TASK_XACCT
 
          Say N if unsure.
 
+config TASK_IO_ACCOUNTING
+       bool "Enable per-task storage I/O accounting (EXPERIMENTAL)"
+       depends on TASK_XACCT
+       help
+         Collect information on the number of bytes of storage I/O which this
+         task has caused.
+
+         Say N if unsure.
+
 config SYSCTL
        bool
 
index 85f04037ade137c6ce452f3183db87527f80e6cf..4fa0f7977de1a16db501d91c3c9b062cb7898c2d 100644 (file)
@@ -526,7 +526,7 @@ static void __init free_initrd(void)
 
 #endif
 
-void __init populate_rootfs(void)
+static int __init populate_rootfs(void)
 {
        char *err = unpack_to_rootfs(__initramfs_start,
                         __initramfs_end - __initramfs_start, 0);
@@ -544,7 +544,7 @@ void __init populate_rootfs(void)
                        unpack_to_rootfs((char *)initrd_start,
                                initrd_end - initrd_start, 0);
                        free_initrd();
-                       return;
+                       return 0;
                }
                printk("it isn't (%s); looks like an initrd\n", err);
                fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
@@ -565,4 +565,6 @@ void __init populate_rootfs(void)
 #endif
        }
 #endif
+       return 0;
 }
+rootfs_initcall(populate_rootfs);
index 036f97c0c34c80bf26a55079e69dcda8f7f0e37d..e3f0bb20b4ddffc0e82181f48ef42e3953df4fdd 100644 (file)
@@ -94,7 +94,6 @@ extern void pidmap_init(void);
 extern void prio_tree_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
-extern void populate_rootfs(void);
 extern void driver_init(void);
 extern void prepare_namespace(void);
 #ifdef CONFIG_ACPI
@@ -483,6 +482,12 @@ void __init __attribute__((weak)) smp_setup_processor_id(void)
 {
 }
 
+static const char linux_banner[] =
+       "Linux version " UTS_RELEASE
+       " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
+       " (" LINUX_COMPILER ")"
+       " " UTS_VERSION "\n";
+
 asmlinkage void __init start_kernel(void)
 {
        char * command_line;
@@ -509,7 +514,7 @@ asmlinkage void __init start_kernel(void)
        boot_cpu_init();
        page_address_init();
        printk(KERN_NOTICE);
-       printk(linux_banner, UTS_RELEASE, UTS_VERSION);
+       printk(linux_banner);
        setup_arch(&command_line);
        unwind_setup();
        setup_per_cpu_areas();
@@ -739,12 +744,6 @@ static int init(void * unused)
 
        cpuset_init_smp();
 
-       /*
-        * Do this before initcalls, because some drivers want to access
-        * firmware files.
-        */
-       populate_rootfs();
-
        do_basic_setup();
 
        /*
index 2a5dfcd1c2e6a373bb81dfa100b786e133066316..9d96d36501ca512d96565daab53e7eb47863a18e 100644 (file)
@@ -33,8 +33,3 @@ struct uts_namespace init_uts_ns = {
        },
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
-
-const char linux_banner[] =
-       "Linux version %s (" LINUX_COMPILE_BY "@"
-       LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") %s\n";
-
index 03e64fe4a14af6b12a1b3638e6d54263a589af47..122fadb972fc2dd9ff3fda5cf15c3c0432a50007 100644 (file)
@@ -425,7 +425,7 @@ static void close_files(struct files_struct * files)
        for (;;) {
                unsigned long set;
                i = j * __NFDBITS;
-               if (i >= fdt->max_fdset || i >= fdt->max_fds)
+               if (i >= fdt->max_fds)
                        break;
                set = fdt->open_fds->fds_bits[j++];
                while (set) {
@@ -466,11 +466,9 @@ void fastcall put_files_struct(struct files_struct *files)
                 * you can free files immediately.
                 */
                fdt = files_fdtable(files);
-               if (fdt == &files->fdtab)
-                       fdt->free_files = files;
-               else
+               if (fdt != &files->fdtab)
                        kmem_cache_free(files_cachep, files);
-               free_fdtable(fdt);
+               call_rcu(&fdt->rcu, free_fdtable_rcu);
        }
 }
 
index 8c859eef8e6a5b825612b750608f452459626643..d16c566eb645a6b7aae1bd7dd5a5489eeb3d3db9 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/syscalls.h>
 #include <linux/jiffies.h>
 #include <linux/futex.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/rcupdate.h>
 #include <linux/ptrace.h>
 #include <linux/mount.h>
@@ -613,7 +614,7 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
 
 static int count_open_files(struct fdtable *fdt)
 {
-       int size = fdt->max_fdset;
+       int size = fdt->max_fds;
        int i;
 
        /* Find the last open fd */
@@ -640,12 +641,10 @@ static struct files_struct *alloc_files(void)
        newf->next_fd = 0;
        fdt = &newf->fdtab;
        fdt->max_fds = NR_OPEN_DEFAULT;
-       fdt->max_fdset = EMBEDDED_FD_SET_SIZE;
        fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;
        fdt->open_fds = (fd_set *)&newf->open_fds_init;
        fdt->fd = &newf->fd_array[0];
        INIT_RCU_HEAD(&fdt->rcu);
-       fdt->free_files = NULL;
        fdt->next = NULL;
        rcu_assign_pointer(newf->fdt, fdt);
 out:
@@ -661,7 +660,7 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
 {
        struct files_struct *newf;
        struct file **old_fds, **new_fds;
-       int open_files, size, i, expand;
+       int open_files, size, i;
        struct fdtable *old_fdt, *new_fdt;
 
        *errorp = -ENOMEM;
@@ -672,25 +671,14 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
        spin_lock(&oldf->file_lock);
        old_fdt = files_fdtable(oldf);
        new_fdt = files_fdtable(newf);
-       size = old_fdt->max_fdset;
        open_files = count_open_files(old_fdt);
-       expand = 0;
 
        /*
-        * Check whether we need to allocate a larger fd array or fd set.
-        * Note: we're not a clone task, so the open count won't  change.
+        * Check whether we need to allocate a larger fd array and fd set.
+        * Note: we're not a clone task, so the open count won't change.
         */
-       if (open_files > new_fdt->max_fdset) {
-               new_fdt->max_fdset = 0;
-               expand = 1;
-       }
        if (open_files > new_fdt->max_fds) {
                new_fdt->max_fds = 0;
-               expand = 1;
-       }
-
-       /* if the old fdset gets grown now, we'll only copy up to "size" fds */
-       if (expand) {
                spin_unlock(&oldf->file_lock);
                spin_lock(&newf->file_lock);
                *errorp = expand_files(newf, open_files-1);
@@ -710,8 +698,10 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
        old_fds = old_fdt->fd;
        new_fds = new_fdt->fd;
 
-       memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8);
-       memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8);
+       memcpy(new_fdt->open_fds->fds_bits,
+               old_fdt->open_fds->fds_bits, open_files/8);
+       memcpy(new_fdt->close_on_exec->fds_bits,
+               old_fdt->close_on_exec->fds_bits, open_files/8);
 
        for (i = open_files; i != 0; i--) {
                struct file *f = *old_fds++;
@@ -736,22 +726,19 @@ static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
        /* This is long word aligned thus could use a optimized version */ 
        memset(new_fds, 0, size); 
 
-       if (new_fdt->max_fdset > open_files) {
-               int left = (new_fdt->max_fdset-open_files)/8;
+       if (new_fdt->max_fds > open_files) {
+               int left = (new_fdt->max_fds-open_files)/8;
                int start = open_files / (8 * sizeof(unsigned long));
 
                memset(&new_fdt->open_fds->fds_bits[start], 0, left);
                memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
        }
 
-out:
        return newf;
 
 out_release:
-       free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset);
-       free_fdset (new_fdt->open_fds, new_fdt->max_fdset);
-       free_fd_array(new_fdt->fd, new_fdt->max_fds);
        kmem_cache_free(files_cachep, newf);
+out:
        return NULL;
 }
 
@@ -1055,6 +1042,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->wchar = 0;           /* I/O counter: bytes written */
        p->syscr = 0;           /* I/O counter: read syscalls */
        p->syscw = 0;           /* I/O counter: write syscalls */
+       task_io_accounting_init(p);
        acct_clear_integrals(p);
 
        p->it_virt_expires = cputime_zero;
index f385eff4682d7fbf169accde4c93d0bf4f42fd83..8a0afb97af71c99f14a01f7974a88886fd7d8f08 100644 (file)
@@ -225,8 +225,10 @@ struct rq {
        unsigned long nr_uninterruptible;
 
        unsigned long expired_timestamp;
-       unsigned long long timestamp_last_tick;
+       /* Cached timestamp set by update_cpu_clock() */
+       unsigned long long most_recent_timestamp;
        struct task_struct *curr, *idle;
+       unsigned long next_balance;
        struct mm_struct *prev_mm;
        struct prio_array *active, *expired, arrays[2];
        int best_expired_prio;
@@ -426,7 +428,7 @@ static inline void task_rq_unlock(struct rq *rq, unsigned long *flags)
  * bump this up when changing the output format or the meaning of an existing
  * format, so that tools can adapt (or abort)
  */
-#define SCHEDSTAT_VERSION 12
+#define SCHEDSTAT_VERSION 14
 
 static int show_schedstat(struct seq_file *seq, void *v)
 {
@@ -464,7 +466,8 @@ static int show_schedstat(struct seq_file *seq, void *v)
                        seq_printf(seq, "domain%d %s", dcnt++, mask_str);
                        for (itype = SCHED_IDLE; itype < MAX_IDLE_TYPES;
                                        itype++) {
-                               seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu",
+                               seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu "
+                                               "%lu",
                                    sd->lb_cnt[itype],
                                    sd->lb_balanced[itype],
                                    sd->lb_failed[itype],
@@ -474,11 +477,13 @@ static int show_schedstat(struct seq_file *seq, void *v)
                                    sd->lb_nobusyq[itype],
                                    sd->lb_nobusyg[itype]);
                        }
-                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+                       seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu"
+                           " %lu %lu %lu\n",
                            sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
                            sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
                            sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
-                           sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance);
+                           sd->ttwu_wake_remote, sd->ttwu_move_affine,
+                           sd->ttwu_move_balance);
                }
                preempt_enable();
 #endif
@@ -547,7 +552,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long delta_jiffies)
 #endif
 
 /*
- * rq_lock - lock a given runqueue and disable interrupts.
+ * this_rq_lock - lock this runqueue and disable interrupts.
  */
 static inline struct rq *this_rq_lock(void)
        __acquires(rq->lock)
@@ -938,13 +943,16 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
 {
        unsigned long long now;
 
+       if (rt_task(p))
+               goto out;
+
        now = sched_clock();
 #ifdef CONFIG_SMP
        if (!local) {
                /* Compensate for drifting sched_clock */
                struct rq *this_rq = this_rq();
-               now = (now - this_rq->timestamp_last_tick)
-                       + rq->timestamp_last_tick;
+               now = (now - this_rq->most_recent_timestamp)
+                       + rq->most_recent_timestamp;
        }
 #endif
 
@@ -959,8 +967,7 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
                                     (now - p->timestamp) >> 20);
        }
 
-       if (!rt_task(p))
-               p->prio = recalc_task_prio(p, now);
+       p->prio = recalc_task_prio(p, now);
 
        /*
         * This checks to make sure it's not an uninterruptible task
@@ -985,7 +992,7 @@ static void activate_task(struct task_struct *p, struct rq *rq, int local)
                }
        }
        p->timestamp = now;
-
+out:
        __activate_task(p, rq);
 }
 
@@ -1450,7 +1457,9 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)
 
                if (this_sd->flags & SD_WAKE_AFFINE) {
                        unsigned long tl = this_load;
-                       unsigned long tl_per_task = cpu_avg_load_per_task(this_cpu);
+                       unsigned long tl_per_task;
+
+                       tl_per_task = cpu_avg_load_per_task(this_cpu);
 
                        /*
                         * If sync wakeup then subtract the (maximum possible)
@@ -1688,8 +1697,8 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
                 * Not the local CPU - must adjust timestamp. This should
                 * get optimised away in the !CONFIG_SMP case.
                 */
-               p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
-                                       + rq->timestamp_last_tick;
+               p->timestamp = (p->timestamp - this_rq->most_recent_timestamp)
+                                       + rq->most_recent_timestamp;
                __activate_task(p, rq);
                if (TASK_PREEMPTS_CURR(p, rq))
                        resched_task(rq->curr);
@@ -1952,6 +1961,7 @@ static void double_rq_lock(struct rq *rq1, struct rq *rq2)
        __acquires(rq1->lock)
        __acquires(rq2->lock)
 {
+       BUG_ON(!irqs_disabled());
        if (rq1 == rq2) {
                spin_lock(&rq1->lock);
                __acquire(rq2->lock);   /* Fake it out ;) */
@@ -1991,6 +2001,11 @@ static void double_lock_balance(struct rq *this_rq, struct rq *busiest)
        __acquires(busiest->lock)
        __acquires(this_rq->lock)
 {
+       if (unlikely(!irqs_disabled())) {
+               /* printk() doesn't work good under rq->lock */
+               spin_unlock(&this_rq->lock);
+               BUG_ON(1);
+       }
        if (unlikely(!spin_trylock(&busiest->lock))) {
                if (busiest < this_rq) {
                        spin_unlock(&this_rq->lock);
@@ -2061,8 +2076,8 @@ static void pull_task(struct rq *src_rq, struct prio_array *src_array,
        set_task_cpu(p, this_cpu);
        inc_nr_running(p, this_rq);
        enqueue_task(p, this_array);
-       p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
-                               + this_rq->timestamp_last_tick;
+       p->timestamp = (p->timestamp - src_rq->most_recent_timestamp)
+                               + this_rq->most_recent_timestamp;
        /*
         * Note that idle threads have a prio of MAX_PRIO, for this test
         * to be always true for them.
@@ -2098,10 +2113,15 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
         * 2) too many balance attempts have failed.
         */
 
-       if (sd->nr_balance_failed > sd->cache_nice_tries)
+       if (sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+               if (task_hot(p, rq->most_recent_timestamp, sd))
+                       schedstat_inc(sd, lb_hot_gained[idle]);
+#endif
                return 1;
+       }
 
-       if (task_hot(p, rq->timestamp_last_tick, sd))
+       if (task_hot(p, rq->most_recent_timestamp, sd))
                return 0;
        return 1;
 }
@@ -2199,11 +2219,6 @@ skip_queue:
                goto skip_bitmap;
        }
 
-#ifdef CONFIG_SCHEDSTATS
-       if (task_hot(tmp, busiest->timestamp_last_tick, sd))
-               schedstat_inc(sd, lb_hot_gained[idle]);
-#endif
-
        pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
        pulled++;
        rem_load_move -= tmp->load_weight;
@@ -2241,7 +2256,7 @@ out:
 static struct sched_group *
 find_busiest_group(struct sched_domain *sd, int this_cpu,
                   unsigned long *imbalance, enum idle_type idle, int *sd_idle,
-                  cpumask_t *cpus)
+                  cpumask_t *cpus, int *balance)
 {
        struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
        unsigned long max_load, avg_load, total_load, this_load, total_pwr;
@@ -2270,10 +2285,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                unsigned long load, group_capacity;
                int local_group;
                int i;
+               unsigned int balance_cpu = -1, first_idle_cpu = 0;
                unsigned long sum_nr_running, sum_weighted_load;
 
                local_group = cpu_isset(this_cpu, group->cpumask);
 
+               if (local_group)
+                       balance_cpu = first_cpu(group->cpumask);
+
                /* Tally up the load of all CPUs in the group */
                sum_weighted_load = sum_nr_running = avg_load = 0;
 
@@ -2289,9 +2308,14 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                                *sd_idle = 0;
 
                        /* Bias balancing toward cpus of our domain */
-                       if (local_group)
+                       if (local_group) {
+                               if (idle_cpu(i) && !first_idle_cpu) {
+                                       first_idle_cpu = 1;
+                                       balance_cpu = i;
+                               }
+
                                load = target_load(i, load_idx);
-                       else
+                       else
                                load = source_load(i, load_idx);
 
                        avg_load += load;
@@ -2299,6 +2323,16 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
                        sum_weighted_load += rq->raw_weighted_load;
                }
 
+               /*
+                * First idle cpu or the first cpu(busiest) in this sched group
+                * is eligible for doing load balancing at this and above
+                * domains.
+                */
+               if (local_group && balance_cpu != this_cpu && balance) {
+                       *balance = 0;
+                       goto ret;
+               }
+
                total_load += avg_load;
                total_pwr += group->cpu_power;
 
@@ -2458,18 +2492,21 @@ small_imbalance:
                pwr_now /= SCHED_LOAD_SCALE;
 
                /* Amount of load we'd subtract */
-               tmp = busiest_load_per_task*SCHED_LOAD_SCALE/busiest->cpu_power;
+               tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
+                       busiest->cpu_power;
                if (max_load > tmp)
                        pwr_move += busiest->cpu_power *
                                min(busiest_load_per_task, max_load - tmp);
 
                /* Amount of load we'd add */
-               if (max_load*busiest->cpu_power <
-                               busiest_load_per_task*SCHED_LOAD_SCALE)
-                       tmp = max_load*busiest->cpu_power/this->cpu_power;
+               if (max_load * busiest->cpu_power <
+                               busiest_load_per_task * SCHED_LOAD_SCALE)
+                       tmp = max_load * busiest->cpu_power / this->cpu_power;
                else
-                       tmp = busiest_load_per_task*SCHED_LOAD_SCALE/this->cpu_power;
-               pwr_move += this->cpu_power*min(this_load_per_task, this_load + tmp);
+                       tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
+                               this->cpu_power;
+               pwr_move += this->cpu_power *
+                       min(this_load_per_task, this_load + tmp);
                pwr_move /= SCHED_LOAD_SCALE;
 
                /* Move if we gain throughput */
@@ -2490,8 +2527,8 @@ out_balanced:
                *imbalance = min_load_per_task;
                return group_min;
        }
-ret:
 #endif
+ret:
        *imbalance = 0;
        return NULL;
 }
@@ -2540,17 +2577,17 @@ static inline unsigned long minus_1_or_zero(unsigned long n)
 /*
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
- *
- * Called with this_rq unlocked.
  */
 static int load_balance(int this_cpu, struct rq *this_rq,
-                       struct sched_domain *sd, enum idle_type idle)
+                       struct sched_domain *sd, enum idle_type idle,
+                       int *balance)
 {
        int nr_moved, all_pinned = 0, active_balance = 0, sd_idle = 0;
        struct sched_group *group;
        unsigned long imbalance;
        struct rq *busiest;
        cpumask_t cpus = CPU_MASK_ALL;
+       unsigned long flags;
 
        /*
         * When power savings policy is enabled for the parent domain, idle
@@ -2566,7 +2603,11 @@ static int load_balance(int this_cpu, struct rq *this_rq,
 
 redo:
        group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
-                                                       &cpus);
+                                  &cpus, balance);
+
+       if (*balance == 0)
+               goto out_balanced;
+
        if (!group) {
                schedstat_inc(sd, lb_nobusyg[idle]);
                goto out_balanced;
@@ -2590,11 +2631,13 @@ redo:
                 * still unbalanced. nr_moved simply stays zero, so it is
                 * correctly treated as an imbalance.
                 */
+               local_irq_save(flags);
                double_rq_lock(this_rq, busiest);
                nr_moved = move_tasks(this_rq, this_cpu, busiest,
                                      minus_1_or_zero(busiest->nr_running),
                                      imbalance, sd, idle, &all_pinned);
                double_rq_unlock(this_rq, busiest);
+               local_irq_restore(flags);
 
                /* All tasks on this runqueue were pinned by CPU affinity */
                if (unlikely(all_pinned)) {
@@ -2611,13 +2654,13 @@ redo:
 
                if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
 
-                       spin_lock(&busiest->lock);
+                       spin_lock_irqsave(&busiest->lock, flags);
 
                        /* don't kick the migration_thread, if the curr
                         * task on busiest cpu can't be moved to this_cpu
                         */
                        if (!cpu_isset(this_cpu, busiest->curr->cpus_allowed)) {
-                               spin_unlock(&busiest->lock);
+                               spin_unlock_irqrestore(&busiest->lock, flags);
                                all_pinned = 1;
                                goto out_one_pinned;
                        }
@@ -2627,7 +2670,7 @@ redo:
                                busiest->push_cpu = this_cpu;
                                active_balance = 1;
                        }
-                       spin_unlock(&busiest->lock);
+                       spin_unlock_irqrestore(&busiest->lock, flags);
                        if (active_balance)
                                wake_up_process(busiest->migration_thread);
 
@@ -2706,7 +2749,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
        schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
 redo:
        group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE,
-                               &sd_idle, &cpus);
+                                  &sd_idle, &cpus, NULL);
        if (!group) {
                schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
                goto out_balanced;
@@ -2766,14 +2809,28 @@ out_balanced:
 static void idle_balance(int this_cpu, struct rq *this_rq)
 {
        struct sched_domain *sd;
+       int pulled_task = 0;
+       unsigned long next_balance = jiffies + 60 *  HZ;
 
        for_each_domain(this_cpu, sd) {
                if (sd->flags & SD_BALANCE_NEWIDLE) {
                        /* If we've pulled tasks over stop searching: */
-                       if (load_balance_newidle(this_cpu, this_rq, sd))
+                       pulled_task = load_balance_newidle(this_cpu,
+                                                       this_rq, sd);
+                       if (time_after(next_balance,
+                                 sd->last_balance + sd->balance_interval))
+                               next_balance = sd->last_balance
+                                               + sd->balance_interval;
+                       if (pulled_task)
                                break;
                }
        }
+       if (!pulled_task)
+               /*
+                * We are going idle. next_balance may be set based on
+                * a busy processor. So reset next_balance.
+                */
+               this_rq->next_balance = next_balance;
 }
 
 /*
@@ -2826,26 +2883,9 @@ static void active_load_balance(struct rq *busiest_rq, int busiest_cpu)
        spin_unlock(&target_rq->lock);
 }
 
-/*
- * rebalance_tick will get called every timer tick, on every CPU.
- *
- * It checks each scheduling domain to see if it is due to be balanced,
- * and initiates a balancing operation if so.
- *
- * Balancing parameters are set up in arch_init_sched_domains.
- */
-
-/* Don't have all balancing operations going off at once: */
-static inline unsigned long cpu_offset(int cpu)
+static void update_load(struct rq *this_rq)
 {
-       return jiffies + cpu * HZ / NR_CPUS;
-}
-
-static void
-rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
-{
-       unsigned long this_load, interval, j = cpu_offset(this_cpu);
-       struct sched_domain *sd;
+       unsigned long this_load;
        int i, scale;
 
        this_load = this_rq->raw_weighted_load;
@@ -2865,6 +2905,32 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
                        new_load += scale-1;
                this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) / scale;
        }
+}
+
+/*
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
+ *
+ * It checks each scheduling domain to see if it is due to be balanced,
+ * and initiates a balancing operation if so.
+ *
+ * Balancing parameters are set up in arch_init_sched_domains.
+ */
+static DEFINE_SPINLOCK(balancing);
+
+static void run_rebalance_domains(struct softirq_action *h)
+{
+       int this_cpu = smp_processor_id(), balance = 1;
+       struct rq *this_rq = cpu_rq(this_cpu);
+       unsigned long interval;
+       struct sched_domain *sd;
+       /*
+        * We are idle if there are no processes running. This
+        * is valid even if we are the idle process (SMT).
+        */
+       enum idle_type idle = !this_rq->nr_running ?
+                               SCHED_IDLE : NOT_IDLE;
+       /* Earliest time when we have to call run_rebalance_domains again */
+       unsigned long next_balance = jiffies + 60*HZ;
 
        for_each_domain(this_cpu, sd) {
                if (!(sd->flags & SD_LOAD_BALANCE))
@@ -2879,8 +2945,13 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
                if (unlikely(!interval))
                        interval = 1;
 
-               if (j - sd->last_balance >= interval) {
-                       if (load_balance(this_cpu, this_rq, sd, idle)) {
+               if (sd->flags & SD_SERIALIZE) {
+                       if (!spin_trylock(&balancing))
+                               goto out;
+               }
+
+               if (time_after_eq(jiffies, sd->last_balance + interval)) {
+                       if (load_balance(this_cpu, this_rq, sd, idle, &balance)) {
                                /*
                                 * We've pulled tasks over so either we're no
                                 * longer idle, or one of our SMT siblings is
@@ -2888,39 +2959,48 @@ rebalance_tick(int this_cpu, struct rq *this_rq, enum idle_type idle)
                                 */
                                idle = NOT_IDLE;
                        }
-                       sd->last_balance += interval;
+                       sd->last_balance = jiffies;
                }
+               if (sd->flags & SD_SERIALIZE)
+                       spin_unlock(&balancing);
+out:
+               if (time_after(next_balance, sd->last_balance + interval))
+                       next_balance = sd->last_balance + interval;
+
+               /*
+                * Stop the load balance at this level. There is another
+                * CPU in our sched group which is doing load balancing more
+                * actively.
+                */
+               if (!balance)
+                       break;
        }
+       this_rq->next_balance = next_balance;
 }
 #else
 /*
  * on UP we do not need to balance between CPUs:
  */
-static inline void rebalance_tick(int cpu, struct rq *rq, enum idle_type idle)
-{
-}
 static inline void idle_balance(int cpu, struct rq *rq)
 {
 }
 #endif
 
-static inline int wake_priority_sleeper(struct rq *rq)
+static inline void wake_priority_sleeper(struct rq *rq)
 {
-       int ret = 0;
-
 #ifdef CONFIG_SCHED_SMT
+       if (!rq->nr_running)
+               return;
+
        spin_lock(&rq->lock);
        /*
         * If an SMT sibling task has been put to sleep for priority
         * reasons reschedule the idle task to see if it can now run.
         */
-       if (rq->nr_running) {
+       if (rq->nr_running)
                resched_task(rq->idle);
-               ret = 1;
-       }
        spin_unlock(&rq->lock);
 #endif
-       return ret;
 }
 
 DEFINE_PER_CPU(struct kernel_stat, kstat);
@@ -2934,7 +3014,8 @@ EXPORT_PER_CPU_SYMBOL(kstat);
 static inline void
 update_cpu_clock(struct task_struct *p, struct rq *rq, unsigned long long now)
 {
-       p->sched_time += now - max(p->timestamp, rq->timestamp_last_tick);
+       p->sched_time += now - p->last_ran;
+       p->last_ran = rq->most_recent_timestamp = now;
 }
 
 /*
@@ -2947,8 +3028,7 @@ unsigned long long current_sched_time(const struct task_struct *p)
        unsigned long flags;
 
        local_irq_save(flags);
-       ns = max(p->timestamp, task_rq(p)->timestamp_last_tick);
-       ns = p->sched_time + sched_clock() - ns;
+       ns = p->sched_time + sched_clock() - p->last_ran;
        local_irq_restore(flags);
 
        return ns;
@@ -3048,35 +3128,12 @@ void account_steal_time(struct task_struct *p, cputime_t steal)
                cpustat->steal = cputime64_add(cpustat->steal, tmp);
 }
 
-/*
- * This function gets called by the timer code, with HZ frequency.
- * We call it with interrupts disabled.
- *
- * It also gets called by the fork code, when changing the parent's
- * timeslices.
- */
-void scheduler_tick(void)
+static void task_running_tick(struct rq *rq, struct task_struct *p)
 {
-       unsigned long long now = sched_clock();
-       struct task_struct *p = current;
-       int cpu = smp_processor_id();
-       struct rq *rq = cpu_rq(cpu);
-
-       update_cpu_clock(p, rq, now);
-
-       rq->timestamp_last_tick = now;
-
-       if (p == rq->idle) {
-               if (wake_priority_sleeper(rq))
-                       goto out;
-               rebalance_tick(cpu, rq, SCHED_IDLE);
-               return;
-       }
-
-       /* Task might have expired already, but not scheduled off yet */
        if (p->array != rq->active) {
+               /* Task has expired but was not scheduled yet */
                set_tsk_need_resched(p);
-               goto out;
+               return;
        }
        spin_lock(&rq->lock);
        /*
@@ -3144,8 +3201,34 @@ void scheduler_tick(void)
        }
 out_unlock:
        spin_unlock(&rq->lock);
-out:
-       rebalance_tick(cpu, rq, NOT_IDLE);
+}
+
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ *
+ * It also gets called by the fork code, when changing the parent's
+ * timeslices.
+ */
+void scheduler_tick(void)
+{
+       unsigned long long now = sched_clock();
+       struct task_struct *p = current;
+       int cpu = smp_processor_id();
+       struct rq *rq = cpu_rq(cpu);
+
+       update_cpu_clock(p, rq, now);
+
+       if (p == rq->idle)
+               /* Task on the idle queue */
+               wake_priority_sleeper(rq);
+       else
+               task_running_tick(rq, p);
+#ifdef CONFIG_SMP
+       update_load(rq);
+       if (time_after_eq(jiffies, rq->next_balance))
+               raise_softirq(SCHED_SOFTIRQ);
+#endif
 }
 
 #ifdef CONFIG_SCHED_SMT
@@ -3291,7 +3374,8 @@ void fastcall add_preempt_count(int val)
        /*
         * Spinlock count overflowing soon?
         */
-       DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >= PREEMPT_MASK-10);
+       DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
+                               PREEMPT_MASK - 10);
 }
 EXPORT_SYMBOL(add_preempt_count);
 
@@ -4990,8 +5074,8 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
                 * afterwards, and pretending it was a local activate.
                 * This way is cleaner and logically correct.
                 */
-               p->timestamp = p->timestamp - rq_src->timestamp_last_tick
-                               + rq_dest->timestamp_last_tick;
+               p->timestamp = p->timestamp - rq_src->most_recent_timestamp
+                               + rq_dest->most_recent_timestamp;
                deactivate_task(p, rq_src);
                __activate_task(p, rq_dest);
                if (TASK_PREEMPTS_CURR(p, rq_dest))
@@ -5067,7 +5151,10 @@ wait_to_die:
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-/* Figure out where task on dead CPU should go, use force if neccessary. */
+/*
+ * Figure out where task on dead CPU should go, use force if neccessary.
+ * NOTE: interrupts should be disabled by the caller
+ */
 static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p)
 {
        unsigned long flags;
@@ -5187,6 +5274,7 @@ void idle_task_exit(void)
        mmdrop(mm);
 }
 
+/* called under rq->lock with disabled interrupts */
 static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
 {
        struct rq *rq = cpu_rq(dead_cpu);
@@ -5203,10 +5291,11 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
         * Drop lock around migration; if someone else moves it,
         * that's OK.  No task can be added to this CPU, so iteration is
         * fine.
+        * NOTE: interrupts should be left disabled  --dev@
         */
-       spin_unlock_irq(&rq->lock);
+       spin_unlock(&rq->lock);
        move_task_off_dead_cpu(dead_cpu, p);
-       spin_lock_irq(&rq->lock);
+       spin_lock(&rq->lock);
 
        put_task_struct(p);
 }
@@ -5359,16 +5448,19 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
                if (!(sd->flags & SD_LOAD_BALANCE)) {
                        printk("does not load-balance\n");
                        if (sd->parent)
-                               printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain has parent");
+                               printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain"
+                                               " has parent");
                        break;
                }
 
                printk("span %s\n", str);
 
                if (!cpu_isset(cpu, sd->span))
-                       printk(KERN_ERR "ERROR: domain->span does not contain CPU%d\n", cpu);
+                       printk(KERN_ERR "ERROR: domain->span does not contain "
+                                       "CPU%d\n", cpu);
                if (!cpu_isset(cpu, group->cpumask))
-                       printk(KERN_ERR "ERROR: domain->groups does not contain CPU%d\n", cpu);
+                       printk(KERN_ERR "ERROR: domain->groups does not contain"
+                                       " CPU%d\n", cpu);
 
                printk(KERN_DEBUG);
                for (i = 0; i < level + 2; i++)
@@ -5383,7 +5475,8 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
 
                        if (!group->cpu_power) {
                                printk("\n");
-                               printk(KERN_ERR "ERROR: domain->cpu_power not set\n");
+                               printk(KERN_ERR "ERROR: domain->cpu_power not "
+                                               "set\n");
                        }
 
                        if (!cpus_weight(group->cpumask)) {
@@ -5406,15 +5499,17 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
                printk("\n");
 
                if (!cpus_equal(sd->span, groupmask))
-                       printk(KERN_ERR "ERROR: groups don't span domain->span\n");
+                       printk(KERN_ERR "ERROR: groups don't span "
+                                       "domain->span\n");
 
                level++;
                sd = sd->parent;
+               if (!sd)
+                       continue;
 
-               if (sd) {
-                       if (!cpus_subset(groupmask, sd->span))
-                               printk(KERN_ERR "ERROR: parent span is not a superset of domain->span\n");
-               }
+               if (!cpus_subset(groupmask, sd->span))
+                       printk(KERN_ERR "ERROR: parent span is not a superset "
+                               "of domain->span\n");
 
        } while (sd);
 }
@@ -5528,28 +5623,27 @@ static int __init isolated_cpu_setup(char *str)
 __setup ("isolcpus=", isolated_cpu_setup);
 
 /*
- * init_sched_build_groups takes an array of groups, the cpumask we wish
- * to span, and a pointer to a function which identifies what group a CPU
- * belongs to. The return value of group_fn must be a valid index into the
- * groups[] array, and must be >= 0 and < NR_CPUS (due to the fact that we
- * keep track of groups covered with a cpumask_t).
+ * init_sched_build_groups takes the cpumask we wish to span, and a pointer
+ * to a function which identifies what group(along with sched group) a CPU
+ * belongs to. The return value of group_fn must be a >= 0 and < NR_CPUS
+ * (due to the fact that we keep track of groups covered with a cpumask_t).
  *
  * init_sched_build_groups will build a circular linked list of the groups
  * covered by the given span, and will set each group's ->cpumask correctly,
  * and ->cpu_power to 0.
  */
 static void
-init_sched_build_groups(struct sched_group groups[], cpumask_t span,
-                       const cpumask_t *cpu_map,
-                       int (*group_fn)(int cpu, const cpumask_t *cpu_map))
+init_sched_build_groups(cpumask_t span, const cpumask_t *cpu_map,
+                       int (*group_fn)(int cpu, const cpumask_t *cpu_map,
+                                       struct sched_group **sg))
 {
        struct sched_group *first = NULL, *last = NULL;
        cpumask_t covered = CPU_MASK_NONE;
        int i;
 
        for_each_cpu_mask(i, span) {
-               int group = group_fn(i, cpu_map);
-               struct sched_group *sg = &groups[group];
+               struct sched_group *sg;
+               int group = group_fn(i, cpu_map, &sg);
                int j;
 
                if (cpu_isset(i, covered))
@@ -5559,7 +5653,7 @@ init_sched_build_groups(struct sched_group groups[], cpumask_t span,
                sg->cpu_power = 0;
 
                for_each_cpu_mask(j, span) {
-                       if (group_fn(j, cpu_map) != group)
+                       if (group_fn(j, cpu_map, NULL) != group)
                                continue;
 
                        cpu_set(j, covered);
@@ -5733,8 +5827,9 @@ __setup("max_cache_size=", setup_max_cache_size);
  */
 static void touch_cache(void *__cache, unsigned long __size)
 {
-       unsigned long size = __size/sizeof(long), chunk1 = size/3,
-                       chunk2 = 2*size/3;
+       unsigned long size = __size / sizeof(long);
+       unsigned long chunk1 = size / 3;
+       unsigned long chunk2 = 2 * size / 3;
        unsigned long *cache = __cache;
        int i;
 
@@ -5843,11 +5938,11 @@ measure_cost(int cpu1, int cpu2, void *cache, unsigned int size)
         */
        measure_one(cache, size, cpu1, cpu2);
        for (i = 0; i < ITERATIONS; i++)
-               cost1 += measure_one(cache, size - i*1024, cpu1, cpu2);
+               cost1 += measure_one(cache, size - i * 1024, cpu1, cpu2);
 
        measure_one(cache, size, cpu2, cpu1);
        for (i = 0; i < ITERATIONS; i++)
-               cost1 += measure_one(cache, size - i*1024, cpu2, cpu1);
+               cost1 += measure_one(cache, size - i * 1024, cpu2, cpu1);
 
        /*
         * (We measure the non-migrating [cached] cost on both
@@ -5857,17 +5952,17 @@ measure_cost(int cpu1, int cpu2, void *cache, unsigned int size)
 
        measure_one(cache, size, cpu1, cpu1);
        for (i = 0; i < ITERATIONS; i++)
-               cost2 += measure_one(cache, size - i*1024, cpu1, cpu1);
+               cost2 += measure_one(cache, size - i * 1024, cpu1, cpu1);
 
        measure_one(cache, size, cpu2, cpu2);
        for (i = 0; i < ITERATIONS; i++)
-               cost2 += measure_one(cache, size - i*1024, cpu2, cpu2);
+               cost2 += measure_one(cache, size - i * 1024, cpu2, cpu2);
 
        /*
         * Get the per-iteration migration cost:
         */
-       do_div(cost1, 2*ITERATIONS);
-       do_div(cost2, 2*ITERATIONS);
+       do_div(cost1, 2 * ITERATIONS);
+       do_div(cost2, 2 * ITERATIONS);
 
        return cost1 - cost2;
 }
@@ -5905,7 +6000,7 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2)
         */
        cache = vmalloc(max_size);
        if (!cache) {
-               printk("could not vmalloc %d bytes for cache!\n", 2*max_size);
+               printk("could not vmalloc %d bytes for cache!\n", 2 * max_size);
                return 1000000; /* return 1 msec on very small boxen */
        }
 
@@ -5930,7 +6025,8 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2)
                avg_fluct = (avg_fluct + fluct)/2;
 
                if (migration_debug)
-                       printk("-> [%d][%d][%7d] %3ld.%ld [%3ld.%ld] (%ld): (%8Ld %8Ld)\n",
+                       printk("-> [%d][%d][%7d] %3ld.%ld [%3ld.%ld] (%ld): "
+                               "(%8Ld %8Ld)\n",
                                cpu1, cpu2, size,
                                (long)cost / 1000000,
                                ((long)cost / 100000) % 10,
@@ -6025,20 +6121,18 @@ static void calibrate_migration_costs(const cpumask_t *cpu_map)
                        -1
 #endif
                );
-       if (system_state == SYSTEM_BOOTING) {
-               if (num_online_cpus() > 1) {
-                       printk("migration_cost=");
-                       for (distance = 0; distance <= max_distance; distance++) {
-                               if (distance)
-                                       printk(",");
-                               printk("%ld", (long)migration_cost[distance] / 1000);
-                       }
-                       printk("\n");
+       if (system_state == SYSTEM_BOOTING && num_online_cpus() > 1) {
+               printk("migration_cost=");
+               for (distance = 0; distance <= max_distance; distance++) {
+                       if (distance)
+                               printk(",");
+                       printk("%ld", (long)migration_cost[distance] / 1000);
                }
+               printk("\n");
        }
        j1 = jiffies;
        if (migration_debug)
-               printk("migration: %ld seconds\n", (j1-j0)/HZ);
+               printk("migration: %ld seconds\n", (j1-j0) / HZ);
 
        /*
         * Move back to the original CPU. NUMA-Q gets confused
@@ -6135,10 +6229,13 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
  */
 #ifdef CONFIG_SCHED_SMT
 static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static struct sched_group sched_group_cpus[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_cpus);
 
-static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map,
+                           struct sched_group **sg)
 {
+       if (sg)
+               *sg = &per_cpu(sched_group_cpus, cpu);
        return cpu;
 }
 #endif
@@ -6148,39 +6245,52 @@ static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
  */
 #ifdef CONFIG_SCHED_MC
 static DEFINE_PER_CPU(struct sched_domain, core_domains);
-static struct sched_group sched_group_core[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_core);
 #endif
 
 #if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
-static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map,
+                            struct sched_group **sg)
 {
+       int group;
        cpumask_t mask = cpu_sibling_map[cpu];
        cpus_and(mask, mask, *cpu_map);
-       return first_cpu(mask);
+       group = first_cpu(mask);
+       if (sg)
+               *sg = &per_cpu(sched_group_core, group);
+       return group;
 }
 #elif defined(CONFIG_SCHED_MC)
-static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map,
+                            struct sched_group **sg)
 {
+       if (sg)
+               *sg = &per_cpu(sched_group_core, cpu);
        return cpu;
 }
 #endif
 
 static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group sched_group_phys[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_phys);
 
-static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map,
+                            struct sched_group **sg)
 {
+       int group;
 #ifdef CONFIG_SCHED_MC
        cpumask_t mask = cpu_coregroup_map(cpu);
        cpus_and(mask, mask, *cpu_map);
-       return first_cpu(mask);
+       group = first_cpu(mask);
 #elif defined(CONFIG_SCHED_SMT)
        cpumask_t mask = cpu_sibling_map[cpu];
        cpus_and(mask, mask, *cpu_map);
-       return first_cpu(mask);
+       group = first_cpu(mask);
 #else
-       return cpu;
+       group = cpu;
 #endif
+       if (sg)
+               *sg = &per_cpu(sched_group_phys, group);
+       return group;
 }
 
 #ifdef CONFIG_NUMA
@@ -6193,12 +6303,22 @@ static DEFINE_PER_CPU(struct sched_domain, node_domains);
 static struct sched_group **sched_group_nodes_bycpu[NR_CPUS];
 
 static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
-static struct sched_group *sched_group_allnodes_bycpu[NR_CPUS];
+static DEFINE_PER_CPU(struct sched_group, sched_group_allnodes);
 
-static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map)
+static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map,
+                                struct sched_group **sg)
 {
-       return cpu_to_node(cpu);
+       cpumask_t nodemask = node_to_cpumask(cpu_to_node(cpu));
+       int group;
+
+       cpus_and(nodemask, nodemask, *cpu_map);
+       group = first_cpu(nodemask);
+
+       if (sg)
+               *sg = &per_cpu(sched_group_allnodes, group);
+       return group;
 }
+
 static void init_numa_sched_groups_power(struct sched_group *group_head)
 {
        struct sched_group *sg = group_head;
@@ -6234,16 +6354,9 @@ static void free_sched_groups(const cpumask_t *cpu_map)
        int cpu, i;
 
        for_each_cpu_mask(cpu, *cpu_map) {
-               struct sched_group *sched_group_allnodes
-                       = sched_group_allnodes_bycpu[cpu];
                struct sched_group **sched_group_nodes
                        = sched_group_nodes_bycpu[cpu];
 
-               if (sched_group_allnodes) {
-                       kfree(sched_group_allnodes);
-                       sched_group_allnodes_bycpu[cpu] = NULL;
-               }
-
                if (!sched_group_nodes)
                        continue;
 
@@ -6337,7 +6450,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        struct sched_domain *sd;
 #ifdef CONFIG_NUMA
        struct sched_group **sched_group_nodes = NULL;
-       struct sched_group *sched_group_allnodes = NULL;
+       int sd_allnodes = 0;
 
        /*
         * Allocate the per-node list of sched groups
@@ -6355,7 +6468,6 @@ static int build_sched_domains(const cpumask_t *cpu_map)
         * Set up domains for cpus specified by the cpu_map.
         */
        for_each_cpu_mask(i, *cpu_map) {
-               int group;
                struct sched_domain *sd = NULL, *p;
                cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
 
@@ -6364,26 +6476,12 @@ static int build_sched_domains(const cpumask_t *cpu_map)
 #ifdef CONFIG_NUMA
                if (cpus_weight(*cpu_map)
                                > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
-                       if (!sched_group_allnodes) {
-                               sched_group_allnodes
-                                       = kmalloc_node(sizeof(struct sched_group)
-                                                       * MAX_NUMNODES,
-                                                 GFP_KERNEL,
-                                                 cpu_to_node(i));
-                               if (!sched_group_allnodes) {
-                                       printk(KERN_WARNING
-                                       "Can not alloc allnodes sched group\n");
-                                       goto error;
-                               }
-                               sched_group_allnodes_bycpu[i]
-                                               = sched_group_allnodes;
-                       }
                        sd = &per_cpu(allnodes_domains, i);
                        *sd = SD_ALLNODES_INIT;
                        sd->span = *cpu_map;
-                       group = cpu_to_allnodes_group(i, cpu_map);
-                       sd->groups = &sched_group_allnodes[group];
+                       cpu_to_allnodes_group(i, cpu_map, &sd->groups);
                        p = sd;
+                       sd_allnodes = 1;
                } else
                        p = NULL;
 
@@ -6398,36 +6496,33 @@ static int build_sched_domains(const cpumask_t *cpu_map)
 
                p = sd;
                sd = &per_cpu(phys_domains, i);
-               group = cpu_to_phys_group(i, cpu_map);
                *sd = SD_CPU_INIT;
                sd->span = nodemask;
                sd->parent = p;
                if (p)
                        p->child = sd;
-               sd->groups = &sched_group_phys[group];
+               cpu_to_phys_group(i, cpu_map, &sd->groups);
 
 #ifdef CONFIG_SCHED_MC
                p = sd;
                sd = &per_cpu(core_domains, i);
-               group = cpu_to_core_group(i, cpu_map);
                *sd = SD_MC_INIT;
                sd->span = cpu_coregroup_map(i);
                cpus_and(sd->span, sd->span, *cpu_map);
                sd->parent = p;
                p->child = sd;
-               sd->groups = &sched_group_core[group];
+               cpu_to_core_group(i, cpu_map, &sd->groups);
 #endif
 
 #ifdef CONFIG_SCHED_SMT
                p = sd;
                sd = &per_cpu(cpu_domains, i);
-               group = cpu_to_cpu_group(i, cpu_map);
                *sd = SD_SIBLING_INIT;
                sd->span = cpu_sibling_map[i];
                cpus_and(sd->span, sd->span, *cpu_map);
                sd->parent = p;
                p->child = sd;
-               sd->groups = &sched_group_cpus[group];
+               cpu_to_cpu_group(i, cpu_map, &sd->groups);
 #endif
        }
 
@@ -6439,8 +6534,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                if (i != first_cpu(this_sibling_map))
                        continue;
 
-               init_sched_build_groups(sched_group_cpus, this_sibling_map,
-                                       cpu_map, &cpu_to_cpu_group);
+               init_sched_build_groups(this_sibling_map, cpu_map, &cpu_to_cpu_group);
        }
 #endif
 
@@ -6451,8 +6545,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                cpus_and(this_core_map, this_core_map, *cpu_map);
                if (i != first_cpu(this_core_map))
                        continue;
-               init_sched_build_groups(sched_group_core, this_core_map,
-                                       cpu_map, &cpu_to_core_group);
+               init_sched_build_groups(this_core_map, cpu_map, &cpu_to_core_group);
        }
 #endif
 
@@ -6465,15 +6558,13 @@ static int build_sched_domains(const cpumask_t *cpu_map)
                if (cpus_empty(nodemask))
                        continue;
 
-               init_sched_build_groups(sched_group_phys, nodemask,
-                                       cpu_map, &cpu_to_phys_group);
+               init_sched_build_groups(nodemask, cpu_map, &cpu_to_phys_group);
        }
 
 #ifdef CONFIG_NUMA
        /* Set up node groups */
-       if (sched_group_allnodes)
-               init_sched_build_groups(sched_group_allnodes, *cpu_map,
-                                       cpu_map, &cpu_to_allnodes_group);
+       if (sd_allnodes)
+               init_sched_build_groups(*cpu_map, cpu_map, &cpu_to_allnodes_group);
 
        for (i = 0; i < MAX_NUMNODES; i++) {
                /* Set up node groups */
@@ -6565,10 +6656,10 @@ static int build_sched_domains(const cpumask_t *cpu_map)
        for (i = 0; i < MAX_NUMNODES; i++)
                init_numa_sched_groups_power(sched_group_nodes[i]);
 
-       if (sched_group_allnodes) {
-               int group = cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map);
-               struct sched_group *sg = &sched_group_allnodes[group];
+       if (sd_allnodes) {
+               struct sched_group *sg;
 
+               cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map, &sg);
                init_numa_sched_groups_power(sg);
        }
 #endif
@@ -6847,6 +6938,10 @@ void __init sched_init(void)
 
        set_load_weight(&init_task);
 
+#ifdef CONFIG_SMP
+       open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);
+#endif
+
 #ifdef CONFIG_RT_MUTEXES
        plist_head_init(&init_task.pi_waiters, &init_task.pi_lock);
 #endif
index 025fcb3c66f87ce7b81c6dc6b3271dc28cbd5085..130c5ec9ee0b3f699c3da72617db844154ce5910 100644 (file)
@@ -133,7 +133,7 @@ extern int max_lock_depth;
 
 #ifdef CONFIG_SYSCTL_SYSCALL
 static int parse_table(int __user *, int, void __user *, size_t __user *,
-               void __user *, size_t, ctl_table *, void **);
+               void __user *, size_t, ctl_table *);
 #endif
 
 static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
@@ -141,12 +141,12 @@ static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
 
 static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context);
+                 void __user *newval, size_t newlen);
 
 #ifdef CONFIG_SYSVIPC
 static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context);
+                 void __user *newval, size_t newlen);
 #endif
 
 #ifdef CONFIG_PROC_SYSCTL
@@ -1243,7 +1243,6 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
        do {
                struct ctl_table_header *head =
                        list_entry(tmp, struct ctl_table_header, ctl_entry);
-               void *context = NULL;
 
                if (!use_table(head))
                        continue;
@@ -1251,9 +1250,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
                spin_unlock(&sysctl_lock);
 
                error = parse_table(name, nlen, oldval, oldlenp, 
-                                       newval, newlen, head->ctl_table,
-                                       &context);
-               kfree(context);
+                                       newval, newlen, head->ctl_table);
 
                spin_lock(&sysctl_lock);
                unuse_table(head);
@@ -1309,7 +1306,7 @@ static inline int ctl_perm(ctl_table *table, int op)
 static int parse_table(int __user *name, int nlen,
                       void __user *oldval, size_t __user *oldlenp,
                       void __user *newval, size_t newlen,
-                      ctl_table *table, void **context)
+                      ctl_table *table)
 {
        int n;
 repeat:
@@ -1329,7 +1326,7 @@ repeat:
                                        error = table->strategy(
                                                table, name, nlen,
                                                oldval, oldlenp,
-                                               newval, newlen, context);
+                                               newval, newlen);
                                        if (error)
                                                return error;
                                }
@@ -1340,7 +1337,7 @@ repeat:
                        }
                        error = do_sysctl_strategy(table, name, nlen,
                                                   oldval, oldlenp,
-                                                  newval, newlen, context);
+                                                  newval, newlen);
                        return error;
                }
        }
@@ -1351,7 +1348,7 @@ repeat:
 int do_sysctl_strategy (ctl_table *table, 
                        int __user *name, int nlen,
                        void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen, void **context)
+                       void __user *newval, size_t newlen)
 {
        int op = 0, rc;
        size_t len;
@@ -1365,7 +1362,7 @@ int do_sysctl_strategy (ctl_table *table,
 
        if (table->strategy) {
                rc = table->strategy(table, name, nlen, oldval, oldlenp,
-                                    newval, newlen, context);
+                                    newval, newlen);
                if (rc < 0)
                        return rc;
                if (rc > 0)
@@ -1931,9 +1928,6 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
 
 #define OP_SET 0
 #define OP_AND 1
-#define OP_OR  2
-#define OP_MAX 3
-#define OP_MIN 4
 
 static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
                                      int *valp,
@@ -1945,13 +1939,6 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
                switch(op) {
                case OP_SET:    *valp = val; break;
                case OP_AND:    *valp &= val; break;
-               case OP_OR:     *valp |= val; break;
-               case OP_MAX:    if(*valp < val)
-                                       *valp = val;
-                               break;
-               case OP_MIN:    if(*valp > val)
-                               *valp = val;
-                               break;
                }
        } else {
                int val = *valp;
@@ -2408,6 +2395,17 @@ static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
 {
        return -ENOSYS;
 }
+static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
+               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       return -ENOSYS;
+}
+static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
+               struct file *filp, void __user *buffer,
+               size_t *lenp, loff_t *ppos)
+{
+       return -ENOSYS;
+}
 #endif
 
 int proc_dointvec(ctl_table *table, int write, struct file *filp,
@@ -2472,7 +2470,7 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
 /* The generic string strategy routine: */
 int sysctl_string(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context)
+                 void __user *newval, size_t newlen)
 {
        if (!table->data || !table->maxlen) 
                return -ENOTDIR;
@@ -2518,7 +2516,7 @@ int sysctl_string(ctl_table *table, int __user *name, int nlen,
  */
 int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
 
        if (newval && newlen) {
@@ -2554,7 +2552,7 @@ int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
 /* Strategy function to convert jiffies to seconds */ 
 int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        if (oldval) {
                size_t olen;
@@ -2582,7 +2580,7 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
 /* Strategy function to convert jiffies to seconds */ 
 int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        if (oldval) {
                size_t olen;
@@ -2611,7 +2609,7 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
 /* The generic string strategy routine: */
 static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context)
+                 void __user *newval, size_t newlen)
 {
        struct ctl_table uts_table;
        int r, write;
@@ -2619,7 +2617,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
        memcpy(&uts_table, table, sizeof(uts_table));
        uts_table.data = get_uts(table, write);
        r = sysctl_string(&uts_table, name, nlen,
-               oldval, oldlenp, newval, newlen, context);
+               oldval, oldlenp, newval, newlen);
        put_uts(table, write, uts_table.data);
        return r;
 }
@@ -2628,7 +2626,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
 /* The generic sysctl ipc data routine. */
 static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        size_t len;
        void *data;
@@ -2703,41 +2701,41 @@ out:
 
 int sysctl_string(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context)
+                 void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
 int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
 int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
 int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 
 static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
                  void __user *oldval, size_t __user *oldlenp,
-                 void __user *newval, size_t newlen, void **context)
+                 void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
 static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
                void __user *oldval, size_t __user *oldlenp,
-               void __user *newval, size_t newlen, void **context)
+               void __user *newval, size_t newlen)
 {
        return -ENOSYS;
 }
index 74eca5939bd989af76da55213ed5ae634ed9f6bd..22504afc0d34b48bf10e216c72b33c3be4470598 100644 (file)
@@ -156,7 +156,7 @@ int clocksource_register(struct clocksource *c)
        /* check if clocksource is already registered */
        if (is_registered_source(c)) {
                printk("register_clocksource: Cannot register %s. "
-                       "Already registered!", c->name);
+                      "Already registered!", c->name);
                ret = -EBUSY;
        } else {
                /* register it */
@@ -186,6 +186,7 @@ void clocksource_reselect(void)
 }
 EXPORT_SYMBOL(clocksource_reselect);
 
+#ifdef CONFIG_SYSFS
 /**
  * sysfs_show_current_clocksources - sysfs interface for current clocksource
  * @dev:       unused
@@ -275,10 +276,10 @@ sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
  * Sysfs setup bits:
  */
 static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
-                       sysfs_override_clocksource);
+                  sysfs_override_clocksource);
 
 static SYSDEV_ATTR(available_clocksource, 0600,
-                       sysfs_show_available_clocksources, NULL);
+                  sysfs_show_available_clocksources, NULL);
 
 static struct sysdev_class clocksource_sysclass = {
        set_kset_name("clocksource"),
@@ -307,6 +308,7 @@ static int __init init_clocksource_sysfs(void)
 }
 
 device_initcall(init_clocksource_sysfs);
+#endif /* CONFIG_SYSFS */
 
 /**
  * boot_override_clocksource - boot clock override
index c1c7fbcffec1615e84a380c2994659cde6216947..0256ab443d8a36445f2ab755b08503c2e28cdd9c 100644 (file)
@@ -80,6 +80,138 @@ tvec_base_t boot_tvec_bases;
 EXPORT_SYMBOL(boot_tvec_bases);
 static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases;
 
+/**
+ * __round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long __round_jiffies(unsigned long j, int cpu)
+{
+       int rem;
+       unsigned long original = j;
+
+       /*
+        * We don't want all cpus firing their timers at once hitting the
+        * same lock or cachelines, so we skew each extra cpu with an extra
+        * 3 jiffies. This 3 jiffies came originally from the mm/ code which
+        * already did this.
+        * The skew is done by adding 3*cpunr, then round, then subtract this
+        * extra offset again.
+        */
+       j += cpu * 3;
+
+       rem = j % HZ;
+
+       /*
+        * If the target jiffie is just after a whole second (which can happen
+        * due to delays of the timer irq, long irq off times etc etc) then
+        * we should round down to the whole second, not up. Use 1/4th second
+        * as cutoff for this rounding as an extreme upper bound for this.
+        */
+       if (rem < HZ/4) /* round down */
+               j = j - rem;
+       else /* round up */
+               j = j - rem + HZ;
+
+       /* now that we have rounded, subtract the extra skew again */
+       j -= cpu * 3;
+
+       if (j <= jiffies) /* rounding ate our timeout entirely; */
+               return original;
+       return j;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies);
+
+/**
+ * __round_jiffies_relative - function to round jiffies to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ * @cpu: the processor number on which the timeout will happen
+ *
+ * __round_jiffies_relative rounds a time delta  in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The exact rounding is skewed for each processor to avoid all
+ * processors firing at the exact same time, which could lead
+ * to lock contention or spurious cache line bouncing.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long __round_jiffies_relative(unsigned long j, int cpu)
+{
+       /*
+        * In theory the following code can skip a jiffy in case jiffies
+        * increments right between the addition and the later subtraction.
+        * However since the entire point of this function is to use approximate
+        * timeouts, it's entirely ok to not handle that.
+        */
+       return  __round_jiffies(j + jiffies, cpu) - jiffies;
+}
+EXPORT_SYMBOL_GPL(__round_jiffies_relative);
+
+/**
+ * round_jiffies - function to round jiffies to a full second
+ * @j: the time in (absolute) jiffies that should be rounded
+ *
+ * round_jiffies rounds an absolute time in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long round_jiffies(unsigned long j)
+{
+       return __round_jiffies(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies);
+
+/**
+ * round_jiffies_relative - function to round jiffies to a full second
+ * @j: the time in (relative) jiffies that should be rounded
+ *
+ * round_jiffies_relative rounds a time delta  in the future (in jiffies)
+ * up or down to (approximately) full seconds. This is useful for timers
+ * for which the exact time they fire does not matter too much, as long as
+ * they fire approximately every X seconds.
+ *
+ * By rounding these timers to whole seconds, all such timers will fire
+ * at the same time, rather than at various times spread out. The goal
+ * of this is to have the CPU wake up less, which saves power.
+ *
+ * The return value is the rounded version of the "j" parameter.
+ */
+unsigned long round_jiffies_relative(unsigned long j)
+{
+       return __round_jiffies_relative(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL_GPL(round_jiffies_relative);
+
+
 static inline void set_running_timer(tvec_base_t *base,
                                        struct timer_list *timer)
 {
@@ -714,7 +846,7 @@ static int change_clocksource(void)
                clock = new;
                clock->cycle_last = now;
                printk(KERN_INFO "Time: %s clocksource has been installed.\n",
-                                       clock->name);
+                      clock->name);
                return 1;
        } else if (clock->update_callback) {
                return clock->update_callback();
@@ -722,7 +854,10 @@ static int change_clocksource(void)
        return 0;
 }
 #else
-#define change_clocksource() (0)
+static inline int change_clocksource(void)
+{
+       return 0;
+}
 #endif
 
 /**
@@ -820,7 +955,8 @@ device_initcall(timekeeping_init_device);
  * If the error is already larger, we look ahead even further
  * to compensate for late or lost adjustments.
  */
-static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 *offset)
+static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
+                                                s64 *offset)
 {
        s64 tick_error, i;
        u32 look_ahead, adj;
@@ -844,7 +980,8 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval, s64 *
         * Now calculate the error in (1 << look_ahead) ticks, but first
         * remove the single look ahead already included in the error.
         */
-       tick_error = current_tick_length() >> (TICK_LENGTH_SHIFT - clock->shift + 1);
+       tick_error = current_tick_length() >>
+               (TICK_LENGTH_SHIFT - clock->shift + 1);
        tick_error -= clock->xtime_interval >> 1;
        error = ((error - tick_error) >> look_ahead) + tick_error;
 
@@ -896,7 +1033,8 @@ static void clocksource_adjust(struct clocksource *clock, s64 offset)
        clock->mult += adj;
        clock->xtime_interval += interval;
        clock->xtime_nsec -= offset;
-       clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift);
+       clock->error -= (interval - offset) <<
+                       (TICK_LENGTH_SHIFT - clock->shift);
 }
 
 /**
index 96f77013d3f038ea03b688c448e2ef69a77aee06..baacc36914152271e01343e5a4de233e7b8780ba 100644 (file)
@@ -96,6 +96,15 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
        stats->write_char       = p->wchar;
        stats->read_syscalls    = p->syscr;
        stats->write_syscalls   = p->syscw;
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+       stats->read_bytes       = p->ioac.read_bytes;
+       stats->write_bytes      = p->ioac.write_bytes;
+       stats->cancelled_write_bytes = p->ioac.cancelled_write_bytes;
+#else
+       stats->read_bytes       = 0;
+       stats->write_bytes      = 0;
+       stats->cancelled_write_bytes = 0;
+#endif
 }
 #undef KB
 #undef MB
index 6eccc643c32edc3e2b11920ba17c1bd73ba11609..0701ddda1df8a48ea41e4456e2bce70943622be1 100644 (file)
@@ -47,6 +47,30 @@ config UNUSED_SYMBOLS
          you really need it, and what the merge plan to the mainline kernel for
          your module is.
 
+config DEBUG_FS
+       bool "Debug Filesystem"
+       depends on SYSFS
+       help
+         debugfs is a virtual file system that kernel developers use to put
+         debugging files into.  Enable this option to be able to read and
+         write to these files.
+
+         If unsure, say N.
+
+config HEADERS_CHECK
+       bool "Run 'make headers_check' when building vmlinux"
+       depends on !UML
+       help
+         This option will extract the user-visible kernel headers whenever
+         building the kernel, and will run basic sanity checks on them to
+         ensure that exported files do not attempt to include files which
+         were not exported, etc.
+
+         If you're making modifications to header files which are
+         relevant for userspace, say 'Y', and check the headers
+         exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
+         your build tree), to make sure they're suitable.
+
 config DEBUG_KERNEL
        bool "Kernel debugging"
        help
@@ -302,16 +326,6 @@ config DEBUG_INFO
 
          If unsure, say N.
 
-config DEBUG_FS
-       bool "Debug Filesystem"
-       depends on SYSFS
-       help
-         debugfs is a virtual file system that kernel developers use to put
-         debugging files into.  Enable this option to be able to read and
-         write to these files.
-
-         If unsure, say N.
-
 config DEBUG_VM
        bool "Debug VM"
        depends on DEBUG_KERNEL
@@ -372,20 +386,6 @@ config FORCED_INLINING
          become the default in the future, until then this option is there to
          test gcc for this.
 
-config HEADERS_CHECK
-       bool "Run 'make headers_check' when building vmlinux"
-       depends on !UML
-       help
-         This option will extract the user-visible kernel headers whenever
-         building the kernel, and will run basic sanity checks on them to
-         ensure that exported files do not attempt to include files which
-         were not exported, etc.
-
-         If you're making modifications to header files which are
-         relevant for userspace, say 'Y', and check the headers
-         exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
-         your build tree), to make sure they're suitable.
-
 config RCU_TORTURE_TEST
        tristate "torture tests for RCU"
        depends on DEBUG_KERNEL
@@ -402,6 +402,7 @@ config RCU_TORTURE_TEST
 
 config LKDTM
        tristate "Linux Kernel Dump Test Tool Module"
+       depends on DEBUG_KERNEL
        depends on KPROBES
        default n
        help
index f4e1c49c825a91d4ed67f50a49fc793e11b64d0c..989aff73f8816cee306d0f1d747d5e1330b20e66 100644 (file)
@@ -2,6 +2,10 @@
 #include <linux/module.h>
 #include <linux/bitrev.h>
 
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_DESCRIPTION("Bit ordering reversal functions");
+MODULE_LICENSE("GPL");
+
 const u8 byte_rev_table[256] = {
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
index 606432f71b3a17dafd791b46361c29a996beec18..8332c77b1bd123fdd76b2a9b2d966711a45b124b 100644 (file)
@@ -1181,8 +1181,6 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                if (pos < size) {
                        retval = generic_file_direct_IO(READ, iocb,
                                                iov, pos, nr_segs);
-                       if (retval > 0 && !is_sync_kiocb(iocb))
-                               retval = -EIOCBQUEUED;
                        if (retval > 0)
                                *ppos = pos + retval;
                }
@@ -2047,15 +2045,14 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
         * Sync the fs metadata but not the minor inode changes and
         * of course not the data as we did direct DMA for the IO.
         * i_mutex is held, which protects generic_osync_inode() from
-        * livelocking.
+        * livelocking.  AIO O_DIRECT ops attempt to sync metadata here.
         */
-       if (written >= 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+       if ((written >= 0 || written == -EIOCBQUEUED) &&
+           ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
                int err = generic_osync_inode(inode, mapping, OSYNC_METADATA);
                if (err < 0)
                        written = err;
        }
-       if (written == count && !is_sync_kiocb(iocb))
-               written = -EIOCBQUEUED;
        return written;
 }
 EXPORT_SYMBOL(generic_file_direct_write);
index 4198df0dff1c0f026355c1e8538761e81ba7254e..bf6100236e6270336651229acbb2056021a68991 100644 (file)
@@ -1110,23 +1110,29 @@ static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
 {
        pte_t *pte;
        spinlock_t *ptl;
+       int err = 0;
 
        pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
        if (!pte)
-               return -ENOMEM;
+               return -EAGAIN;
        arch_enter_lazy_mmu_mode();
        do {
                struct page *page = ZERO_PAGE(addr);
                pte_t zero_pte = pte_wrprotect(mk_pte(page, prot));
+
+               if (unlikely(!pte_none(*pte))) {
+                       err = -EEXIST;
+                       pte++;
+                       break;
+               }
                page_cache_get(page);
                page_add_file_rmap(page);
                inc_mm_counter(mm, file_rss);
-               BUG_ON(!pte_none(*pte));
                set_pte_at(mm, addr, pte, zero_pte);
        } while (pte++, addr += PAGE_SIZE, addr != end);
        arch_leave_lazy_mmu_mode();
        pte_unmap_unlock(pte - 1, ptl);
-       return 0;
+       return err;
 }
 
 static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
@@ -1134,16 +1140,18 @@ static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
 {
        pmd_t *pmd;
        unsigned long next;
+       int err;
 
        pmd = pmd_alloc(mm, pud, addr);
        if (!pmd)
-               return -ENOMEM;
+               return -EAGAIN;
        do {
                next = pmd_addr_end(addr, end);
-               if (zeromap_pte_range(mm, pmd, addr, next, prot))
-                       return -ENOMEM;
+               err = zeromap_pte_range(mm, pmd, addr, next, prot);
+               if (err)
+                       break;
        } while (pmd++, addr = next, addr != end);
-       return 0;
+       return err;
 }
 
 static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
@@ -1151,16 +1159,18 @@ static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
 {
        pud_t *pud;
        unsigned long next;
+       int err;
 
        pud = pud_alloc(mm, pgd, addr);
        if (!pud)
-               return -ENOMEM;
+               return -EAGAIN;
        do {
                next = pud_addr_end(addr, end);
-               if (zeromap_pmd_range(mm, pud, addr, next, prot))
-                       return -ENOMEM;
+               err = zeromap_pmd_range(mm, pud, addr, next, prot);
+               if (err)
+                       break;
        } while (pud++, addr = next, addr != end);
-       return 0;
+       return err;
 }
 
 int zeromap_page_range(struct vm_area_struct *vma,
index 8d9b19f239c3ec03038e88cdd0a44e8a71c0d3e9..237107c1b0847d79e6139daf5c811ea1c432c087 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/writeback.h>
 #include <linux/init.h>
 #include <linux/backing-dev.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/blkdev.h>
 #include <linux/mpage.h>
 #include <linux/rmap.h>
@@ -761,23 +762,24 @@ int __set_page_dirty_nobuffers(struct page *page)
                struct address_space *mapping = page_mapping(page);
                struct address_space *mapping2;
 
-               if (mapping) {
-                       write_lock_irq(&mapping->tree_lock);
-                       mapping2 = page_mapping(page);
-                       if (mapping2) { /* Race with truncate? */
-                               BUG_ON(mapping2 != mapping);
-                               if (mapping_cap_account_dirty(mapping))
-                                       __inc_zone_page_state(page,
-                                                               NR_FILE_DIRTY);
-                               radix_tree_tag_set(&mapping->page_tree,
-                                       page_index(page), PAGECACHE_TAG_DIRTY);
-                       }
-                       write_unlock_irq(&mapping->tree_lock);
-                       if (mapping->host) {
-                               /* !PageAnon && !swapper_space */
-                               __mark_inode_dirty(mapping->host,
-                                                       I_DIRTY_PAGES);
+               if (!mapping)
+                       return 1;
+
+               write_lock_irq(&mapping->tree_lock);
+               mapping2 = page_mapping(page);
+               if (mapping2) { /* Race with truncate? */
+                       BUG_ON(mapping2 != mapping);
+                       if (mapping_cap_account_dirty(mapping)) {
+                               __inc_zone_page_state(page, NR_FILE_DIRTY);
+                               task_io_account_write(PAGE_CACHE_SIZE);
                        }
+                       radix_tree_tag_set(&mapping->page_tree,
+                               page_index(page), PAGECACHE_TAG_DIRTY);
+               }
+               write_unlock_irq(&mapping->tree_lock);
+               if (mapping->host) {
+                       /* !PageAnon && !swapper_space */
+                       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
                }
                return 1;
        }
@@ -851,27 +853,26 @@ int test_clear_page_dirty(struct page *page)
        struct address_space *mapping = page_mapping(page);
        unsigned long flags;
 
-       if (mapping) {
-               write_lock_irqsave(&mapping->tree_lock, flags);
-               if (TestClearPageDirty(page)) {
-                       radix_tree_tag_clear(&mapping->page_tree,
-                                               page_index(page),
-                                               PAGECACHE_TAG_DIRTY);
-                       write_unlock_irqrestore(&mapping->tree_lock, flags);
-                       /*
-                        * We can continue to use `mapping' here because the
-                        * page is locked, which pins the address_space
-                        */
-                       if (mapping_cap_account_dirty(mapping)) {
-                               page_mkclean(page);
-                               dec_zone_page_state(page, NR_FILE_DIRTY);
-                       }
-                       return 1;
-               }
+       if (!mapping)
+               return TestClearPageDirty(page);
+
+       write_lock_irqsave(&mapping->tree_lock, flags);
+       if (TestClearPageDirty(page)) {
+               radix_tree_tag_clear(&mapping->page_tree,
+                               page_index(page), PAGECACHE_TAG_DIRTY);
                write_unlock_irqrestore(&mapping->tree_lock, flags);
-               return 0;
+               /*
+                * We can continue to use `mapping' here because the
+                * page is locked, which pins the address_space
+                */
+               if (mapping_cap_account_dirty(mapping)) {
+                       page_mkclean(page);
+                       dec_zone_page_state(page, NR_FILE_DIRTY);
+               }
+               return 1;
        }
-       return TestClearPageDirty(page);
+       write_unlock_irqrestore(&mapping->tree_lock, flags);
+       return 0;
 }
 EXPORT_SYMBOL(test_clear_page_dirty);
 
@@ -893,17 +894,17 @@ int clear_page_dirty_for_io(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
 
-       if (mapping) {
-               if (TestClearPageDirty(page)) {
-                       if (mapping_cap_account_dirty(mapping)) {
-                               page_mkclean(page);
-                               dec_zone_page_state(page, NR_FILE_DIRTY);
-                       }
-                       return 1;
+       if (!mapping)
+               return TestClearPageDirty(page);
+
+       if (TestClearPageDirty(page)) {
+               if (mapping_cap_account_dirty(mapping)) {
+                       page_mkclean(page);
+                       dec_zone_page_state(page, NR_FILE_DIRTY);
                }
-               return 0;
+               return 1;
        }
-       return TestClearPageDirty(page);
+       return 0;
 }
 EXPORT_SYMBOL(clear_page_dirty_for_io);
 
index c0df5ed05f624a61d7e685d9b5ff9c4bfa4d2f90..0f539e8e827a7a1b0956c30d30ea89434b02bc26 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/pagevec.h>
 
 void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
@@ -151,6 +152,7 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages,
                        put_pages_list(pages);
                        break;
                }
+               task_io_account_read(PAGE_CACHE_SIZE);
        }
        pagevec_lru_add(&lru_pvec);
        return ret;
index 56af694c9e6a386f75aa718f339a54eef6e27b8d..2c655532f5efcefac182e20cd2bb325decb92407 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -946,7 +946,8 @@ static void __devinit start_cpu_timer(int cpu)
        if (keventd_up() && reap_work->work.func == NULL) {
                init_reap_node(cpu);
                INIT_DELAYED_WORK(reap_work, cache_reap);
-               schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu);
+               schedule_delayed_work_on(cpu, reap_work,
+                                       __round_jiffies_relative(HZ, cpu));
        }
 }
 
@@ -4006,7 +4007,7 @@ static void cache_reap(struct work_struct *unused)
        if (!mutex_trylock(&cache_chain_mutex)) {
                /* Give up. Setup the next iteration. */
                schedule_delayed_work(&__get_cpu_var(reap_work),
-                                     REAPTIMEOUT_CPUC);
+                                     round_jiffies_relative(REAPTIMEOUT_CPUC));
                return;
        }
 
@@ -4052,7 +4053,8 @@ next:
        next_reap_node();
        refresh_cpu_vm_stats(smp_processor_id());
        /* Set up the next iteration */
-       schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC);
+       schedule_delayed_work(&__get_cpu_var(reap_work),
+               round_jiffies_relative(REAPTIMEOUT_CPUC));
 }
 
 #ifdef CONFIG_PROC_FS
index e07b1e682c38f5fca96436904eb1a9a262ce1426..9bfb8e853860df2da0d752948352f87e3c099abd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/buffer_head.h> /* grr. try_to_release_page,
                                   do_invalidatepage */
 
@@ -69,7 +70,8 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
        if (PagePrivate(page))
                do_invalidatepage(page, 0);
 
-       clear_page_dirty(page);
+       if (test_clear_page_dirty(page))
+               task_io_account_cancelled_write(PAGE_CACHE_SIZE);
        ClearPageUptodate(page);
        ClearPageMappedToDisk(page);
        remove_from_page_cache(page);
index 21a0616152fc4d56b72ded295163eeb93c02a3dd..97a49c79c6050df6caf43543caaff4d8bd07b3fc 100644 (file)
@@ -83,7 +83,7 @@ EXPORT_SYMBOL(ax2asc);
  */
 void asc2ax(ax25_address *addr, const char *callsign)
 {
-       char *s;
+       const char *s;
        int n;
 
        for (s = callsign, n = 0; n < 6; n++) {
index 8a271285f2f378d154d21927790e3a31cefd42a3..823215d8e90f6411b6e6fb94ba1ecd9bcae2f6f1 100644 (file)
@@ -55,6 +55,7 @@ static void queue_process(struct work_struct *work)
        struct netpoll_info *npinfo =
                container_of(work, struct netpoll_info, tx_work.work);
        struct sk_buff *skb;
+       unsigned long flags;
 
        while ((skb = skb_dequeue(&npinfo->txq))) {
                struct net_device *dev = skb->dev;
@@ -64,15 +65,19 @@ static void queue_process(struct work_struct *work)
                        continue;
                }
 
-               netif_tx_lock_bh(dev);
+               local_irq_save(flags);
+               netif_tx_lock(dev);
                if (netif_queue_stopped(dev) ||
                    dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
                        skb_queue_head(&npinfo->txq, skb);
-                       netif_tx_unlock_bh(dev);
+                       netif_tx_unlock(dev);
+                       local_irq_restore(flags);
 
                        schedule_delayed_work(&npinfo->tx_work, HZ/10);
                        return;
                }
+               netif_tx_unlock(dev);
+               local_irq_restore(flags);
        }
 }
 
@@ -242,22 +247,28 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 
        /* don't get messages out of order, and no recursion */
        if (skb_queue_len(&npinfo->txq) == 0 &&
-           npinfo->poll_owner != smp_processor_id() &&
-           netif_tx_trylock(dev)) {
-               /* try until next clock tick */
-               for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) {
-                       if (!netif_queue_stopped(dev))
-                               status = dev->hard_start_xmit(skb, dev);
+                   npinfo->poll_owner != smp_processor_id()) {
+               unsigned long flags;
 
-                       if (status == NETDEV_TX_OK)
-                               break;
+               local_irq_save(flags);
+               if (netif_tx_trylock(dev)) {
+                       /* try until next clock tick */
+                       for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
+                                       tries > 0; --tries) {
+                               if (!netif_queue_stopped(dev))
+                                       status = dev->hard_start_xmit(skb, dev);
 
-                       /* tickle device maybe there is some cleanup */
-                       netpoll_poll(np);
+                               if (status == NETDEV_TX_OK)
+                                       break;
+
+                               /* tickle device maybe there is some cleanup */
+                               netpoll_poll(np);
 
-                       udelay(USEC_PER_POLL);
+                               udelay(USEC_PER_POLL);
+                       }
+                       netif_tx_unlock(dev);
                }
-               netif_tx_unlock(dev);
+               local_irq_restore(flags);
        }
 
        if (status != NETDEV_TX_OK) {
index 1f4727ddbdbfbf1e8d1214ed2604bb4a120306ac..a086c6312d3b220c6695dfdb35bac7ac0fc358dc 100644 (file)
@@ -223,7 +223,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
                        gap = -new_head;
                }
                new_head += DCCP_MAX_ACKVEC_LEN;
-       } 
+       }
 
        av->dccpav_buf_head = new_head;
 
@@ -336,7 +336,7 @@ out_duplicate:
 void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len)
 {
        dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len,
-                                       (unsigned long long)ackno);
+                        (unsigned long long)ackno);
 
        while (len--) {
                const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6;
index bcc2d12ae81ccb13d00e428c85840b37a0ac81ec..c65cb2453e43d7836e80ab25059d3993c5d875ce 100644 (file)
@@ -43,8 +43,6 @@ struct ccid_operations {
                                                    unsigned char* value);
        int             (*ccid_hc_rx_insert_options)(struct sock *sk,
                                                     struct sk_buff *skb);
-       int             (*ccid_hc_tx_insert_options)(struct sock *sk,
-                                                    struct sk_buff *skb);
        void            (*ccid_hc_tx_packet_recv)(struct sock *sk,
                                                  struct sk_buff *skb);
        int             (*ccid_hc_tx_parse_options)(struct sock *sk,
@@ -146,14 +144,6 @@ static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
        return rc;
 }
 
-static inline int ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
-                                           struct sk_buff *skb)
-{
-       if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL)
-               return ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
-       return 0;
-}
-
 static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
                                            struct sk_buff *skb)
 {
index 2555be8f4790e4825f861fc97ab502365f5ef786..fd38b05d6f79ec146edda973d2a307653a0c01f8 100644 (file)
@@ -351,7 +351,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
 
                while (seqp != hctx->ccid2hctx_seqh) {
                        ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
-                                      (unsigned long long)seqp->ccid2s_seq,
+                                      (unsigned long long)seqp->ccid2s_seq,
                                       seqp->ccid2s_acked, seqp->ccid2s_sent);
                        seqp = seqp->ccid2s_next;
                }
@@ -473,7 +473,7 @@ static inline void ccid2_new_ack(struct sock *sk,
                /* first measurement */
                if (hctx->ccid2hctx_srtt == -1) {
                        ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
-                                      r, jiffies,
+                                      r, jiffies,
                                       (unsigned long long)seqp->ccid2s_seq);
                        ccid2_change_srtt(hctx, r);
                        hctx->ccid2hctx_rttvar = r >> 1;
@@ -518,8 +518,8 @@ static inline void ccid2_new_ack(struct sock *sk,
                hctx->ccid2hctx_lastrtt = jiffies;
 
                ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
-                              hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
-                              hctx->ccid2hctx_rto, HZ, r);
+                              hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+                              hctx->ccid2hctx_rto, HZ, r);
                hctx->ccid2hctx_sent = 0;
        }
 
@@ -667,9 +667,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                                /* new packet received or marked */
                                if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
                                    !seqp->ccid2s_acked) {
-                                       if (state ==
+                                       if (state ==
                                            DCCP_ACKVEC_STATE_ECN_MARKED) {
-                                               ccid2_congestion_event(hctx,
+                                               ccid2_congestion_event(hctx,
                                                                       seqp);
                                        } else
                                                ccid2_new_ack(sk, seqp,
index 66a27b9688ca9240579ce897df70637b8698eb18..fa6b75372ed701d114ea7f9b9c8596ee5f34f97e 100644 (file)
 #include "lib/tfrc.h"
 #include "ccid3.h"
 
-/*
- * Reason for maths here is to avoid 32 bit overflow when a is big.
- * With this we get close to the limit.
- */
-static u32 usecs_div(const u32 a, const u32 b)
-{
-       const u32 div = a < (UINT_MAX / (USEC_PER_SEC /    10)) ?    10 :
-                       a < (UINT_MAX / (USEC_PER_SEC /    50)) ?    50 :
-                       a < (UINT_MAX / (USEC_PER_SEC /   100)) ?   100 :
-                       a < (UINT_MAX / (USEC_PER_SEC /   500)) ?   500 :
-                       a < (UINT_MAX / (USEC_PER_SEC /  1000)) ?  1000 :
-                       a < (UINT_MAX / (USEC_PER_SEC /  5000)) ?  5000 :
-                       a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 :
-                       a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 :
-                                                                100000;
-       const u32 tmp = a * (USEC_PER_SEC / div);
-       return (b >= 2 * div) ? tmp / (b / div) : tmp;
-}
-
-
-
 #ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 static int ccid3_debug;
 #define ccid3_pr_debug(format, a...)   DCCP_PR_DEBUG(ccid3_debug, format, ##a)
@@ -108,8 +87,9 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
 {
        timeval_sub_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
 
-       /* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */
-       hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x);
+       /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
+       hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s,
+                                          hctx->ccid3hctx_x >> 6);
 
        /* Update nominal send time with regard to the new t_ipi */
        timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
@@ -128,40 +108,44 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
  *          X = max(min(2 * X, 2 * X_recv), s / R);
  *          tld = now;
  *
+ * Note: X and X_recv are both stored in units of 64 * bytes/second, to support
+ *       fine-grained resolution of sending rates. This requires scaling by 2^6
+ *       throughout the code. Only X_calc is unscaled (in bytes/second).
+ *
  * If X has changed, we also update the scheduled send time t_now,
  * the inter-packet interval t_ipi, and the delta value.
- */ 
+ */
 static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)
 
 {
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-       const __u32 old_x = hctx->ccid3hctx_x;
+       const  __u64 old_x = hctx->ccid3hctx_x;
 
        if (hctx->ccid3hctx_p > 0) {
-               hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s,
-                                                    hctx->ccid3hctx_rtt,
-                                                    hctx->ccid3hctx_p);
-               hctx->ccid3hctx_x = max_t(u32, min(hctx->ccid3hctx_x_calc,
-                                                  hctx->ccid3hctx_x_recv * 2),
-                                              hctx->ccid3hctx_s / TFRC_T_MBI);
-
-       } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) >=
-                                                         hctx->ccid3hctx_rtt) {
-               hctx->ccid3hctx_x = max(min(hctx->ccid3hctx_x_recv,
-                                           hctx->ccid3hctx_x      ) * 2,
-                                       usecs_div(hctx->ccid3hctx_s,
-                                                 hctx->ccid3hctx_rtt)   );
+
+               hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6,
+                                       hctx->ccid3hctx_x_recv * 2);
+               hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
+                                       (((__u64)hctx->ccid3hctx_s) << 6) /
+                                                               TFRC_T_MBI);
+
+       } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) -
+                       (suseconds_t)hctx->ccid3hctx_rtt >= 0) {
+
+               hctx->ccid3hctx_x =
+                       max(2 * min(hctx->ccid3hctx_x, hctx->ccid3hctx_x_recv),
+                           scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
+                                      hctx->ccid3hctx_rtt));
                hctx->ccid3hctx_t_ld = *now;
-       } else
-               ccid3_pr_debug("Not changing X\n");
+       }
 
        if (hctx->ccid3hctx_x != old_x)
                ccid3_update_send_time(hctx);
 }
 
 /*
- *     Track the mean packet size `s' (cf. RFC 4342, 5.3 and  RFC 3448, 4.1)
- *     @len: DCCP packet payload size in bytes
+ *     Track the mean packet size `s' (cf. RFC 4342, 5.3 and  RFC 3448, 4.1)
+ *     @len: DCCP packet payload size in bytes
  */
 static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
 {
@@ -178,6 +162,33 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
         */
 }
 
+/*
+ *     Update Window Counter using the algorithm from [RFC 4342, 8.1].
+ *     The algorithm is not applicable if RTT < 4 microseconds.
+ */
+static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
+                                               struct timeval *now)
+{
+       suseconds_t delta;
+       u32 quarter_rtts;
+
+       if (unlikely(hctx->ccid3hctx_rtt < 4))  /* avoid divide-by-zero */
+               return;
+
+       delta = timeval_delta(now, &hctx->ccid3hctx_t_last_win_count);
+       DCCP_BUG_ON(delta < 0);
+
+       quarter_rtts = (u32)delta / (hctx->ccid3hctx_rtt / 4);
+
+       if (quarter_rtts > 0) {
+               hctx->ccid3hctx_t_last_win_count = *now;
+               hctx->ccid3hctx_last_win_count  += min_t(u32, quarter_rtts, 5);
+               hctx->ccid3hctx_last_win_count  &= 0xF;         /* mod 16 */
+
+               ccid3_pr_debug("now at %#X\n", hctx->ccid3hctx_last_win_count);
+       }
+}
+
 static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
 {
        struct sock *sk = (struct sock *)data;
@@ -191,20 +202,20 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
                goto restart_timer;
        }
 
-       ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk,
+       ccid3_pr_debug("%s(%p, state=%s) - entry \n", dccp_role(sk), sk,
                       ccid3_tx_state_name(hctx->ccid3hctx_state));
-       
+
        switch (hctx->ccid3hctx_state) {
        case TFRC_SSTATE_NO_FBACK:
                /* RFC 3448, 4.4: Halve send rate directly */
-               hctx->ccid3hctx_x = min_t(u32, hctx->ccid3hctx_x / 2,
-                                              hctx->ccid3hctx_s / TFRC_T_MBI);
+               hctx->ccid3hctx_x = max(hctx->ccid3hctx_x / 2,
+                                       (((__u64)hctx->ccid3hctx_s) << 6) /
+                                                                   TFRC_T_MBI);
 
-               ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d "
-                              "bytes/s\n",
-                              dccp_role(sk), sk,
+               ccid3_pr_debug("%s(%p, state=%s), updated tx rate to %u "
+                              "bytes/s\n", dccp_role(sk), sk,
                               ccid3_tx_state_name(hctx->ccid3hctx_state),
-                              hctx->ccid3hctx_x);
+                              (unsigned)(hctx->ccid3hctx_x >> 6));
                /* The value of R is still undefined and so we can not recompute
                 * the timout value. Keep initial value as per [RFC 4342, 5]. */
                t_nfb = TFRC_INITIAL_TIMEOUT;
@@ -213,34 +224,46 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
        case TFRC_SSTATE_FBACK:
                /*
                 * Check if IDLE since last timeout and recv rate is less than
-                * 4 packets per RTT
+                * 4 packets (in units of 64*bytes/sec) per RTT
                 */
                if (!hctx->ccid3hctx_idle ||
-                   (hctx->ccid3hctx_x_recv >=
-                    4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) {
+                   (hctx->ccid3hctx_x_recv >= 4 *
+                    scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
+                               hctx->ccid3hctx_rtt))) {
                        struct timeval now;
 
-                       ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n",
+                       ccid3_pr_debug("%s(%p, state=%s), not idle\n",
                                       dccp_role(sk), sk,
-                                      ccid3_tx_state_name(hctx->ccid3hctx_state));
-                       /* Halve sending rate */
+                                  ccid3_tx_state_name(hctx->ccid3hctx_state));
 
-                       /*  If (p == 0 || X_calc > 2 * X_recv)
+                       /*
+                        *  Modify the cached value of X_recv [RFC 3448, 4.4]
+                        *
+                        *  If (p == 0 || X_calc > 2 * X_recv)
                         *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
                         *  Else
                         *    X_recv = X_calc / 4;
+                        *
+                        *  Note that X_recv is scaled by 2^6 while X_calc is not
                         */
                        BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
 
                        if (hctx->ccid3hctx_p  == 0 ||
-                           hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv)
-                               hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2,
-                                                                   hctx->ccid3hctx_s / (2 * TFRC_T_MBI));
-                       else
-                               hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4;
-
-                       /* Update sending rate */
-                       dccp_timestamp(sk, &now);
+                           (hctx->ccid3hctx_x_calc >
+                            (hctx->ccid3hctx_x_recv >> 5))) {
+
+                               hctx->ccid3hctx_x_recv =
+                                       max(hctx->ccid3hctx_x_recv / 2,
+                                           (((__u64)hctx->ccid3hctx_s) << 6) /
+                                                         (2 * TFRC_T_MBI));
+
+                               if (hctx->ccid3hctx_p == 0)
+                                       dccp_timestamp(sk, &now);
+                       } else {
+                               hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
+                               hctx->ccid3hctx_x_recv <<= 4;
+                       }
+                       /* Now recalculate X [RFC 3448, 4.3, step (4)] */
                        ccid3_hc_tx_update_x(sk, &now);
                }
                /*
@@ -251,7 +274,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
                t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
                break;
        case TFRC_SSTATE_NO_SENT:
-               DCCP_BUG("Illegal %s state NO_SENT, sk=%p", dccp_role(sk), sk);
+               DCCP_BUG("%s(%p) - Illegal state NO_SENT", dccp_role(sk), sk);
                /* fall through */
        case TFRC_SSTATE_TERM:
                goto out;
@@ -277,9 +300,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-       struct dccp_tx_hist_entry *new_packet;
        struct timeval now;
-       long delay;
+       suseconds_t delay;
 
        BUG_ON(hctx == NULL);
 
@@ -291,34 +313,21 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
        if (unlikely(skb->len == 0))
                return -EBADMSG;
 
-       /* See if last packet allocated was not sent */
-       new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
-       if (new_packet == NULL || new_packet->dccphtx_sent) {
-               new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist,
-                                                   GFP_ATOMIC);
-
-               if (unlikely(new_packet == NULL)) {
-                       DCCP_WARN("%s, sk=%p, not enough mem to add to history,"
-                                 "send refused\n", dccp_role(sk), sk);
-                       return -ENOBUFS;
-               }
-
-               dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
-       }
-
        dccp_timestamp(sk, &now);
 
        switch (hctx->ccid3hctx_state) {
        case TFRC_SSTATE_NO_SENT:
                sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
-                              jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
+                              (jiffies +
+                               usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
                hctx->ccid3hctx_last_win_count   = 0;
                hctx->ccid3hctx_t_last_win_count = now;
                ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
 
-               /* Set initial sending rate to 1 packet per second */
+               /* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */
                ccid3_hc_tx_update_s(hctx, skb->len);
-               hctx->ccid3hctx_x     = hctx->ccid3hctx_s;
+               hctx->ccid3hctx_x = hctx->ccid3hctx_s;
+               hctx->ccid3hctx_x <<= 6;
 
                /* First timeout, according to [RFC 3448, 4.2], is 1 second */
                hctx->ccid3hctx_t_ipi = USEC_PER_SEC;
@@ -332,77 +341,57 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
        case TFRC_SSTATE_FBACK:
                delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now);
                /*
-                *      Scheduling of packet transmissions [RFC 3448, 4.6]
+                *      Scheduling of packet transmissions [RFC 3448, 4.6]
                 *
                 * if (t_now > t_nom - delta)
                 *       // send the packet now
                 * else
                 *       // send the packet in (t_nom - t_now) milliseconds.
                 */
-               if (delay - (long)hctx->ccid3hctx_delta >= 0)
+               if (delay - (suseconds_t)hctx->ccid3hctx_delta >= 0)
                        return delay / 1000L;
+
+               ccid3_hc_tx_update_win_count(hctx, &now);
                break;
        case TFRC_SSTATE_TERM:
-               DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+               DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
                return -EINVAL;
        }
 
        /* prepare to send now (add options etc.) */
        dp->dccps_hc_tx_insert_options = 1;
-       new_packet->dccphtx_ccval = DCCP_SKB_CB(skb)->dccpd_ccval =
-                                   hctx->ccid3hctx_last_win_count;
+       DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+
+       /* set the nominal send time for the next following packet */
        timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
 
        return 0;
 }
 
-static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
+static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
+                                   unsigned int len)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        struct timeval now;
-       unsigned long quarter_rtt;
        struct dccp_tx_hist_entry *packet;
 
        BUG_ON(hctx == NULL);
 
-       dccp_timestamp(sk, &now);
-
        ccid3_hc_tx_update_s(hctx, len);
 
-       packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+       packet = dccp_tx_hist_entry_new(ccid3_tx_hist, GFP_ATOMIC);
        if (unlikely(packet == NULL)) {
-               DCCP_WARN("packet doesn't exist in history!\n");
-               return;
-       }
-       if (unlikely(packet->dccphtx_sent)) {
-               DCCP_WARN("no unsent packet in history!\n");
+               DCCP_CRIT("packet history - out of memory!");
                return;
        }
-       packet->dccphtx_tstamp = now;
-       packet->dccphtx_seqno  = dp->dccps_gss;
-       /*
-        * Check if win_count have changed
-        * Algorithm in "8.1. Window Counter Value" in RFC 4342.
-        */
-       quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count);
-       if (likely(hctx->ccid3hctx_rtt > 8))
-               quarter_rtt /= hctx->ccid3hctx_rtt / 4;
-
-       if (quarter_rtt > 0) {
-               hctx->ccid3hctx_t_last_win_count = now;
-               hctx->ccid3hctx_last_win_count   = (hctx->ccid3hctx_last_win_count +
-                                                   min_t(unsigned long, quarter_rtt, 5)) % 16;
-               ccid3_pr_debug("%s, sk=%p, window changed from "
-                              "%u to %u!\n",
-                              dccp_role(sk), sk,
-                              packet->dccphtx_ccval,
-                              hctx->ccid3hctx_last_win_count);
-       }
+       dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet);
 
-       hctx->ccid3hctx_idle = 0;
-       packet->dccphtx_rtt  = hctx->ccid3hctx_rtt;
-       packet->dccphtx_sent = 1;
+       dccp_timestamp(sk, &now);
+       packet->dccphtx_tstamp = now;
+       packet->dccphtx_seqno  = dccp_sk(sk)->dccps_gss;
+       packet->dccphtx_rtt    = hctx->ccid3hctx_rtt;
+       packet->dccphtx_sent   = 1;
+       hctx->ccid3hctx_idle   = 0;
 }
 
 static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
@@ -414,7 +403,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        struct timeval now;
        unsigned long t_nfb;
        u32 pinv;
-       long r_sample, t_elapsed;
+       suseconds_t r_sample, t_elapsed;
 
        BUG_ON(hctx == NULL);
 
@@ -430,44 +419,44 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        case TFRC_SSTATE_FBACK:
                /* get packet from history to look up t_recvdata */
                packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
-                                                DCCP_SKB_CB(skb)->dccpd_ack_seq);
+                                             DCCP_SKB_CB(skb)->dccpd_ack_seq);
                if (unlikely(packet == NULL)) {
                        DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist "
                                  "in history!\n",  dccp_role(sk), sk,
                            (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
-                                 dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+                               dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
                        return;
                }
 
-               /* Update receive rate */
+               /* Update receive rate in units of 64 * bytes/second */
                hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;
+               hctx->ccid3hctx_x_recv <<= 6;
 
                /* Update loss event rate */
                pinv = opt_recv->ccid3or_loss_event_rate;
-               if (pinv == ~0U || pinv == 0)
+               if (pinv == ~0U || pinv == 0)          /* see RFC 4342, 8.5   */
                        hctx->ccid3hctx_p = 0;
-               else
-                       hctx->ccid3hctx_p = 1000000 / pinv;
+               else                                   /* can not exceed 100% */
+                       hctx->ccid3hctx_p = 1000000 / pinv;
 
                dccp_timestamp(sk, &now);
 
                /*
                 * Calculate new round trip sample as per [RFC 3448, 4.3] by
-                *      R_sample  =  (now - t_recvdata) - t_elapsed
+                *      R_sample  =  (now - t_recvdata) - t_elapsed
                 */
                r_sample  = timeval_delta(&now, &packet->dccphtx_tstamp);
                t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
 
-               if (unlikely(r_sample <= 0)) {
-                       DCCP_WARN("WARNING: R_sample (%ld) <= 0!\n", r_sample);
-                       r_sample = 0;
-               } else if (unlikely(r_sample <= t_elapsed))
-                       DCCP_WARN("WARNING: r_sample=%ldus <= t_elapsed=%ldus\n",
-                                 r_sample, t_elapsed);
+               DCCP_BUG_ON(r_sample < 0);
+               if (unlikely(r_sample <= t_elapsed))
+                       DCCP_WARN("WARNING: r_sample=%dus <= t_elapsed=%dus\n",
+                                 (int)r_sample, (int)t_elapsed);
                else
                        r_sample -= t_elapsed;
+               CCID3_RTT_SANITY_CHECK(r_sample);
 
-               /* Update RTT estimate by 
+               /* Update RTT estimate by
                 * If (No feedback recv)
                 *    R = R_sample;
                 * Else
@@ -476,34 +465,45 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                 * q is a constant, RFC 3448 recomments 0.9
                 */
                if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
-                       /* Use Larger Initial Windows [RFC 4342, sec. 5]
-                        * We deviate in that we use `s' instead of `MSS'. */
-                       u16 w_init = max(    4 * hctx->ccid3hctx_s,
-                                        max(2 * hctx->ccid3hctx_s, 4380));
+                       /*
+                        * Larger Initial Windows [RFC 4342, sec. 5]
+                        * We deviate in that we use `s' instead of `MSS'.
+                        */
+                       __u64 w_init = min(4 * hctx->ccid3hctx_s,
+                                          max(2 * hctx->ccid3hctx_s, 4380));
                        hctx->ccid3hctx_rtt  = r_sample;
-                       hctx->ccid3hctx_x    = usecs_div(w_init, r_sample);
+                       hctx->ccid3hctx_x    = scaled_div(w_init << 6, r_sample);
                        hctx->ccid3hctx_t_ld = now;
 
                        ccid3_update_send_time(hctx);
 
-                       ccid3_pr_debug("%s(%p), s=%u, w_init=%u, "
-                                      "R_sample=%ldus, X=%u\n", dccp_role(sk),
-                                      sk, hctx->ccid3hctx_s, w_init, r_sample,
-                                      hctx->ccid3hctx_x);
+                       ccid3_pr_debug("%s(%p), s=%u, w_init=%llu, "
+                                      "R_sample=%dus, X=%u\n", dccp_role(sk),
+                                      sk, hctx->ccid3hctx_s, w_init,
+                                      (int)r_sample,
+                                      (unsigned)(hctx->ccid3hctx_x >> 6));
 
                        ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
                } else {
                        hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt +
-                                                  (u32)r_sample        ) / 10;
-
+                                                  (u32)r_sample) / 10;
+
+                       /* Update sending rate (step 4 of [RFC 3448, 4.3]) */
+                       if (hctx->ccid3hctx_p > 0)
+                               hctx->ccid3hctx_x_calc =
+                                       tfrc_calc_x(hctx->ccid3hctx_s,
+                                                   hctx->ccid3hctx_rtt,
+                                                   hctx->ccid3hctx_p);
                        ccid3_hc_tx_update_x(sk, &now);
 
-                       ccid3_pr_debug("%s(%p), RTT=%uus (sample=%ldus), s=%u, "
-                                      "p=%u, X_calc=%u, X=%u\n", dccp_role(sk),
-                                      sk, hctx->ccid3hctx_rtt, r_sample,
+                       ccid3_pr_debug("%s(%p), RTT=%uus (sample=%dus), s=%u, "
+                                      "p=%u, X_calc=%u, X_recv=%u, X=%u\n",
+                                      dccp_role(sk),
+                                      sk, hctx->ccid3hctx_rtt, (int)r_sample,
                                       hctx->ccid3hctx_s, hctx->ccid3hctx_p,
                                       hctx->ccid3hctx_x_calc,
-                                      hctx->ccid3hctx_x);
+                                      (unsigned)(hctx->ccid3hctx_x_recv >> 6),
+                                      (unsigned)(hctx->ccid3hctx_x >> 6));
                }
 
                /* unschedule no feedback timer */
@@ -513,57 +513,48 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                dccp_tx_hist_purge_older(ccid3_tx_hist,
                                         &hctx->ccid3hctx_hist, packet);
                /*
-                * As we have calculated new ipi, delta, t_nom it is possible that
-                * we now can send a packet, so wake up dccp_wait_for_ccid
+                * As we have calculated new ipi, delta, t_nom it is possible
+                * that we now can send a packet, so wake up dccp_wait_for_ccid
                 */
                sk->sk_write_space(sk);
 
                /*
                 * Update timeout interval for the nofeedback timer.
                 * We use a configuration option to increase the lower bound.
-                * This can help avoid triggering the nofeedback timer too often
-                * ('spinning') on LANs with small RTTs.
+                * This can help avoid triggering the nofeedback timer too
+                * often ('spinning') on LANs with small RTTs.
                 */
                hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
                                                   CONFIG_IP_DCCP_CCID3_RTO *
-                                                  (USEC_PER_SEC/1000)       );
+                                                  (USEC_PER_SEC/1000));
                /*
                 * Schedule no feedback timer to expire in
                 * max(t_RTO, 2 * s/X)  =  max(t_RTO, 2 * t_ipi)
                 */
                t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
-                       
-               ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to "
+
+               ccid3_pr_debug("%s(%p), Scheduled no feedback timer to "
                               "expire in %lu jiffies (%luus)\n",
-                              dccp_role(sk), sk,
-                              usecs_to_jiffies(t_nfb), t_nfb);
+                              dccp_role(sk),
+                              sk, usecs_to_jiffies(t_nfb), t_nfb);
 
-               sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, 
+               sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
                                   jiffies + usecs_to_jiffies(t_nfb));
 
                /* set idle flag */
-               hctx->ccid3hctx_idle = 1;   
+               hctx->ccid3hctx_idle = 1;
                break;
        case TFRC_SSTATE_NO_SENT:
-               if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT)
-                       DCCP_WARN("Illegal ACK received - no packet sent\n");
+               /*
+                * XXX when implementing bidirectional rx/tx check this again
+                */
+               DCCP_WARN("Illegal ACK received - no packet sent\n");
                /* fall through */
        case TFRC_SSTATE_TERM:          /* ignore feedback when closing */
                break;
        }
 }
 
-static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
-{
-       const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-
-       BUG_ON(hctx == NULL);
-
-       if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
-               DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
-       return 0;
-}
-
 static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                     unsigned char len, u16 idx,
                                     unsigned char *value)
@@ -588,13 +579,14 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
        switch (option) {
        case TFRC_OPT_LOSS_EVENT_RATE:
                if (unlikely(len != 4)) {
-                       DCCP_WARN("%s, sk=%p, invalid len %d "
+                       DCCP_WARN("%s(%p), invalid len %d "
                                  "for TFRC_OPT_LOSS_EVENT_RATE\n",
                                  dccp_role(sk), sk, len);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value);
-                       ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
+                       opt_recv->ccid3or_loss_event_rate =
+                                               ntohl(*(__be32 *)value);
+                       ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_loss_event_rate);
                }
@@ -602,20 +594,21 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
        case TFRC_OPT_LOSS_INTERVALS:
                opt_recv->ccid3or_loss_intervals_idx = idx;
                opt_recv->ccid3or_loss_intervals_len = len;
-               ccid3_pr_debug("%s, sk=%p, LOSS_INTERVALS=(%u, %u)\n",
+               ccid3_pr_debug("%s(%p), LOSS_INTERVALS=(%u, %u)\n",
                               dccp_role(sk), sk,
                               opt_recv->ccid3or_loss_intervals_idx,
                               opt_recv->ccid3or_loss_intervals_len);
                break;
        case TFRC_OPT_RECEIVE_RATE:
                if (unlikely(len != 4)) {
-                       DCCP_WARN("%s, sk=%p, invalid len %d "
+                       DCCP_WARN("%s(%p), invalid len %d "
                                  "for TFRC_OPT_RECEIVE_RATE\n",
                                  dccp_role(sk), sk, len);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value);
-                       ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
+                       opt_recv->ccid3or_receive_rate =
+                                               ntohl(*(__be32 *)value);
+                       ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_receive_rate);
                }
@@ -630,10 +623,12 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
        struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
 
        hctx->ccid3hctx_s     = 0;
+       hctx->ccid3hctx_rtt   = 0;
        hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
        INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
 
-       hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+       hctx->ccid3hctx_no_feedback_timer.function =
+                               ccid3_hc_tx_no_feedback_timer;
        hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
        init_timer(&hctx->ccid3hctx_no_feedback_timer);
 
@@ -698,8 +693,9 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_rx_hist_entry *packet;
        struct timeval now;
+       suseconds_t delta;
 
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+       ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk);
 
        dccp_timestamp(sk, &now);
 
@@ -707,21 +703,21 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        case TFRC_RSTATE_NO_DATA:
                hcrx->ccid3hcrx_x_recv = 0;
                break;
-       case TFRC_RSTATE_DATA: {
-               const u32 delta = timeval_delta(&now,
-                                       &hcrx->ccid3hcrx_tstamp_last_feedback);
-               hcrx->ccid3hcrx_x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv,
-                                                  delta);
-       }
+       case TFRC_RSTATE_DATA:
+               delta = timeval_delta(&now,
+                                     &hcrx->ccid3hcrx_tstamp_last_feedback);
+               DCCP_BUG_ON(delta < 0);
+               hcrx->ccid3hcrx_x_recv =
+                       scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
                break;
        case TFRC_RSTATE_TERM:
-               DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+               DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
                return;
        }
 
        packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
        if (unlikely(packet == NULL)) {
-               DCCP_WARN("%s, sk=%p, no data packet in history!\n",
+               DCCP_WARN("%s(%p), no data packet in history!\n",
                          dccp_role(sk), sk);
                return;
        }
@@ -730,13 +726,19 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        hcrx->ccid3hcrx_ccval_last_counter   = packet->dccphrx_ccval;
        hcrx->ccid3hcrx_bytes_recv           = 0;
 
-       /* Convert to multiples of 10us */
-       hcrx->ccid3hcrx_elapsed_time =
-                       timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
+       /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */
+       delta = timeval_delta(&now, &packet->dccphrx_tstamp);
+       DCCP_BUG_ON(delta < 0);
+       hcrx->ccid3hcrx_elapsed_time = delta / 10;
+
        if (hcrx->ccid3hcrx_p == 0)
-               hcrx->ccid3hcrx_pinv = ~0;
-       else
+               hcrx->ccid3hcrx_pinv = ~0U;     /* see RFC 4342, 8.5 */
+       else if (hcrx->ccid3hcrx_p > 1000000) {
+               DCCP_WARN("p (%u) > 100%%\n", hcrx->ccid3hcrx_p);
+               hcrx->ccid3hcrx_pinv = 1;       /* use 100% in this case */
+       } else
                hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
+
        dp->dccps_hc_rx_insert_options = 1;
        dccp_send_ack(sk);
 }
@@ -764,9 +766,9 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
                                             hcrx->ccid3hcrx_elapsed_time)) ||
            dccp_insert_option_timestamp(sk, skb) ||
            dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
-                              &pinv, sizeof(pinv)) ||
+                              &pinv, sizeof(pinv)) ||
            dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
-                              &x_recv, sizeof(x_recv)))
+                              &x_recv, sizeof(x_recv)))
                return -1;
 
        return 0;
@@ -780,12 +782,13 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
-       u32 rtt, delta, x_recv, fval, p, tmp2;
+       u32 x_recv, p;
+       suseconds_t rtt, delta;
        struct timeval tstamp = { 0, };
        int interval = 0;
        int win_count = 0;
        int step = 0;
-       u64 tmp1;
+       u64 fval;
 
        list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
                                 dccphrx_node) {
@@ -810,13 +813,13 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
        }
 
        if (unlikely(step == 0)) {
-               DCCP_WARN("%s, sk=%p, packet history has no data packets!\n",
+               DCCP_WARN("%s(%p), packet history has no data packets!\n",
                          dccp_role(sk), sk);
                return ~0;
        }
 
        if (unlikely(interval == 0)) {
-               DCCP_WARN("%s, sk=%p, Could not find a win_count interval > 0."
+               DCCP_WARN("%s(%p), Could not find a win_count interval > 0."
                          "Defaulting to 1\n", dccp_role(sk), sk);
                interval = 1;
        }
@@ -825,41 +828,51 @@ found:
                DCCP_CRIT("tail is null\n");
                return ~0;
        }
-       rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
-       ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
-                      dccp_role(sk), sk, rtt);
 
-       if (rtt == 0) {
-               DCCP_WARN("RTT==0, setting to 1\n");
-               rtt = 1;
+       delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp);
+       DCCP_BUG_ON(delta < 0);
+
+       rtt = delta * 4 / interval;
+       ccid3_pr_debug("%s(%p), approximated RTT to %dus\n",
+                      dccp_role(sk), sk, (int)rtt);
+
+       /*
+        * Determine the length of the first loss interval via inverse lookup.
+        * Assume that X_recv can be computed by the throughput equation
+        *                  s
+        *      X_recv = --------
+        *               R * fval
+        * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1].
+        */
+       if (rtt == 0) {                 /* would result in divide-by-zero */
+               DCCP_WARN("RTT==0, returning 1/p = 1\n");
+               return 1000000;
        }
 
        dccp_timestamp(sk, &tstamp);
        delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
-       x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta);
-
-       if (x_recv == 0)
-               x_recv = hcrx->ccid3hcrx_x_recv;
-
-       tmp1 = (u64)x_recv * (u64)rtt;
-       do_div(tmp1,10000000);
-       tmp2 = (u32)tmp1;
-
-       if (!tmp2) {
-               DCCP_CRIT("tmp2 = 0, x_recv = %u, rtt =%u\n", x_recv, rtt);
-               return ~0;
+       DCCP_BUG_ON(delta <= 0);
+
+       x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+       if (x_recv == 0) {              /* would also trigger divide-by-zero */
+               DCCP_WARN("X_recv==0\n");
+               if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) {
+                       DCCP_BUG("stored value of X_recv is zero");
+                       return 1000000;
+               }
        }
 
-       fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
-       /* do not alter order above or you will get overflow on 32 bit */
+       fval = scaled_div(hcrx->ccid3hcrx_s, rtt);
+       fval = scaled_div32(fval, x_recv);
        p = tfrc_calc_x_reverse_lookup(fval);
-       ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied "
+
+       ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
                       "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
 
        if (p == 0)
                return ~0;
        else
-               return 1000000 / p; 
+               return 1000000 / p;
 }
 
 static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
@@ -913,7 +926,8 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk,
                                     struct dccp_rx_hist_entry *packet)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
+       struct dccp_rx_hist_entry *rx_hist =
+                               dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
        u64 seqno = packet->dccphrx_seqno;
        u64 tmp_seqno;
        int loss = 0;
@@ -941,7 +955,7 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk,
                dccp_inc_seqno(&tmp_seqno);
                while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist,
                   tmp_seqno, &ccval)) {
-                       hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
+                       hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
                        hcrx->ccid3hcrx_ccval_nonloss = ccval;
                        dccp_inc_seqno(&tmp_seqno);
                }
@@ -967,7 +981,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        const struct dccp_options_received *opt_recv;
        struct dccp_rx_hist_entry *packet;
        struct timeval now;
-       u32 p_prev, rtt_prev, r_sample, t_elapsed;
+       u32 p_prev, rtt_prev;
+       suseconds_t r_sample, t_elapsed;
        int loss, payload_size;
 
        BUG_ON(hcrx == NULL);
@@ -987,11 +1002,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                r_sample = timeval_usecs(&now);
                t_elapsed = opt_recv->dccpor_elapsed_time * 10;
 
+               DCCP_BUG_ON(r_sample < 0);
                if (unlikely(r_sample <= t_elapsed))
-                       DCCP_WARN("r_sample=%uus, t_elapsed=%uus\n",
+                       DCCP_WARN("r_sample=%ldus, t_elapsed=%ldus\n",
                                  r_sample, t_elapsed);
                else
                        r_sample -= t_elapsed;
+               CCID3_RTT_SANITY_CHECK(r_sample);
 
                if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
                        hcrx->ccid3hcrx_rtt = r_sample;
@@ -1000,8 +1017,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                                              r_sample / 10;
 
                if (rtt_prev != hcrx->ccid3hcrx_rtt)
-                       ccid3_pr_debug("%s, New RTT=%uus, elapsed time=%u\n",
-                                      dccp_role(sk), hcrx->ccid3hcrx_rtt,
+                       ccid3_pr_debug("%s(%p), New RTT=%uus, elapsed time=%u\n",
+                                      dccp_role(sk), sk, hcrx->ccid3hcrx_rtt,
                                       opt_recv->dccpor_elapsed_time);
                break;
        case DCCP_PKT_DATA:
@@ -1013,7 +1030,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp,
                                        skb, GFP_ATOMIC);
        if (unlikely(packet == NULL)) {
-               DCCP_WARN("%s, sk=%p, Not enough mem to add rx packet "
+               DCCP_WARN("%s(%p), Not enough mem to add rx packet "
                          "to history, consider it lost!\n", dccp_role(sk), sk);
                return;
        }
@@ -1028,9 +1045,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
 
        switch (hcrx->ccid3hcrx_state) {
        case TFRC_RSTATE_NO_DATA:
-               ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial "
-                              "feedback\n",
-                              dccp_role(sk), sk,
+               ccid3_pr_debug("%s(%p, state=%s), skb=%p, sending initial "
+                              "feedback\n", dccp_role(sk), sk,
                               dccp_state_name(sk->sk_state), skb);
                ccid3_hc_rx_send_feedback(sk);
                ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
@@ -1041,19 +1057,19 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                        break;
 
                dccp_timestamp(sk, &now);
-               if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
-                   hcrx->ccid3hcrx_rtt) {
+               if ((timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) -
+                    (suseconds_t)hcrx->ccid3hcrx_rtt) >= 0) {
                        hcrx->ccid3hcrx_tstamp_last_ack = now;
                        ccid3_hc_rx_send_feedback(sk);
                }
                return;
        case TFRC_RSTATE_TERM:
-               DCCP_BUG("Illegal %s state TERM, sk=%p", dccp_role(sk), sk);
+               DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
                return;
        }
 
        /* Dealing with packet loss */
-       ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
+       ccid3_pr_debug("%s(%p, state=%s), data loss! Reacting...\n",
                       dccp_role(sk), sk, dccp_state_name(sk->sk_state));
 
        p_prev = hcrx->ccid3hcrx_p;
@@ -1078,7 +1094,7 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
 
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
+       ccid3_pr_debug("entry\n");
 
        hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
        INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
@@ -1086,7 +1102,7 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
        dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack);
        hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack;
        hcrx->ccid3hcrx_s   = 0;
-       hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */
+       hcrx->ccid3hcrx_rtt = 0;
        return 0;
 }
 
@@ -1115,9 +1131,9 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 
        BUG_ON(hcrx == NULL);
 
-       info->tcpi_ca_state     = hcrx->ccid3hcrx_state;
-       info->tcpi_options      |= TCPI_OPT_TIMESTAMPS;
-       info->tcpi_rcv_rtt      = hcrx->ccid3hcrx_rtt;
+       info->tcpi_ca_state = hcrx->ccid3hcrx_state;
+       info->tcpi_options  |= TCPI_OPT_TIMESTAMPS;
+       info->tcpi_rcv_rtt  = hcrx->ccid3hcrx_rtt;
 }
 
 static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1198,7 +1214,6 @@ static struct ccid_operations ccid3 = {
        .ccid_hc_tx_send_packet    = ccid3_hc_tx_send_packet,
        .ccid_hc_tx_packet_sent    = ccid3_hc_tx_packet_sent,
        .ccid_hc_tx_packet_recv    = ccid3_hc_tx_packet_recv,
-       .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
        .ccid_hc_tx_parse_options  = ccid3_hc_tx_parse_options,
        .ccid_hc_rx_obj_size       = sizeof(struct ccid3_hc_rx_sock),
        .ccid_hc_rx_init           = ccid3_hc_rx_init,
@@ -1210,7 +1225,7 @@ static struct ccid_operations ccid3 = {
        .ccid_hc_rx_getsockopt     = ccid3_hc_rx_getsockopt,
        .ccid_hc_tx_getsockopt     = ccid3_hc_tx_getsockopt,
 };
+
 #ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 module_param(ccid3_debug, int, 0444);
 MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");
@@ -1233,7 +1248,7 @@ static __init int ccid3_module_init(void)
                goto out_free_tx;
 
        rc = ccid_register(&ccid3);
-       if (rc != 0) 
+       if (rc != 0)
                goto out_free_loss_interval_history;
 out:
        return rc;
index 07596d704ef9a67b802885ae739152dc6906e7ea..15776a88c0901c82c876026c42a0eb8b1af0826c 100644 (file)
 /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
 #define TFRC_T_MBI                64
 
+/* What we think is a reasonable upper limit on RTT values */
+#define CCID3_SANE_RTT_MAX        ((suseconds_t)(4 * USEC_PER_SEC))
+
+#define CCID3_RTT_SANITY_CHECK(rtt)                    do {               \
+               if (rtt > CCID3_SANE_RTT_MAX) {                            \
+                       DCCP_CRIT("RTT (%d) too large, substituting %d",   \
+                                 (int)rtt, (int)CCID3_SANE_RTT_MAX);      \
+                       rtt = CCID3_SANE_RTT_MAX;                          \
+               }                                       } while (0)
+
 enum ccid3_options {
        TFRC_OPT_LOSS_EVENT_RATE = 192,
        TFRC_OPT_LOSS_INTERVALS  = 193,
@@ -67,7 +77,7 @@ struct ccid3_options_received {
 
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
-               TFRC_SSTATE_NO_SENT = 1,
+       TFRC_SSTATE_NO_SENT = 1,
        TFRC_SSTATE_NO_FBACK,
        TFRC_SSTATE_FBACK,
        TFRC_SSTATE_TERM,
@@ -75,23 +85,23 @@ enum ccid3_hc_tx_states {
 
 /** struct ccid3_hc_tx_sock - CCID3 sender half-connection socket
  *
- * @ccid3hctx_x - Current sending rate
- * @ccid3hctx_x_recv - Receive rate
- * @ccid3hctx_x_calc - Calculated send rate (RFC 3448, 3.1)
+ * @ccid3hctx_x - Current sending rate in 64 * bytes per second
+ * @ccid3hctx_x_recv - Receive rate    in 64 * bytes per second
+ * @ccid3hctx_x_calc - Calculated rate in bytes per second
  * @ccid3hctx_rtt - Estimate of current round trip time in usecs
  * @ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000
- * @ccid3hctx_s - Packet size
- * @ccid3hctx_t_rto - Retransmission Timeout (RFC 3448, 3.1)
- * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6)
+ * @ccid3hctx_s - Packet size in bytes
+ * @ccid3hctx_t_rto - Nofeedback Timer setting in usecs
+ * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) in usecs
  * @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states
  * @ccid3hctx_last_win_count - Last window counter sent
  * @ccid3hctx_t_last_win_count - Timestamp of earliest packet
- *                              with last_win_count value sent
+ *                              with last_win_count value sent
  * @ccid3hctx_no_feedback_timer - Handle to no feedback timer
  * @ccid3hctx_idle - Flag indicating that sender is idling
  * @ccid3hctx_t_ld - Time last doubled during slow start
  * @ccid3hctx_t_nom - Nominal send time of next packet
- * @ccid3hctx_delta - Send timer delta
+ * @ccid3hctx_delta - Send timer delta (RFC 3448, 4.6) in usecs
  * @ccid3hctx_hist - Packet history
  * @ccid3hctx_options_received - Parsed set of retrieved options
  */
@@ -105,7 +115,7 @@ struct ccid3_hc_tx_sock {
 #define ccid3hctx_t_rto                        ccid3hctx_tfrc.tfrctx_rto
 #define ccid3hctx_t_ipi                        ccid3hctx_tfrc.tfrctx_ipi
        u16                             ccid3hctx_s;
-       enum ccid3_hc_tx_states         ccid3hctx_state:8;
+       enum ccid3_hc_tx_states         ccid3hctx_state:8;
        u8                              ccid3hctx_last_win_count;
        u8                              ccid3hctx_idle;
        struct timeval                  ccid3hctx_t_last_win_count;
@@ -119,7 +129,7 @@ struct ccid3_hc_tx_sock {
 
 /* TFRC receiver states */
 enum ccid3_hc_rx_states {
-               TFRC_RSTATE_NO_DATA = 1,
+       TFRC_RSTATE_NO_DATA = 1,
        TFRC_RSTATE_DATA,
        TFRC_RSTATE_TERM    = 127,
 };
@@ -147,18 +157,18 @@ struct ccid3_hc_rx_sock {
 #define ccid3hcrx_x_recv               ccid3hcrx_tfrc.tfrcrx_x_recv
 #define ccid3hcrx_rtt                  ccid3hcrx_tfrc.tfrcrx_rtt
 #define ccid3hcrx_p                    ccid3hcrx_tfrc.tfrcrx_p
-       u64                             ccid3hcrx_seqno_nonloss:48,
+       u64                             ccid3hcrx_seqno_nonloss:48,
                                        ccid3hcrx_ccval_nonloss:4,
                                        ccid3hcrx_ccval_last_counter:4;
        enum ccid3_hc_rx_states         ccid3hcrx_state:8;
-       u32                             ccid3hcrx_bytes_recv;
-       struct timeval                  ccid3hcrx_tstamp_last_feedback;
-       struct timeval                  ccid3hcrx_tstamp_last_ack;
+       u32                             ccid3hcrx_bytes_recv;
+       struct timeval                  ccid3hcrx_tstamp_last_feedback;
+       struct timeval                  ccid3hcrx_tstamp_last_ack;
        struct list_head                ccid3hcrx_hist;
        struct list_head                ccid3hcrx_li_hist;
-       u16                             ccid3hcrx_s;
-       u32                             ccid3hcrx_pinv;
-       u32                             ccid3hcrx_elapsed_time;
+       u16                             ccid3hcrx_s;
+       u32                             ccid3hcrx_pinv;
+       u32                             ccid3hcrx_elapsed_time;
 };
 
 static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
index b876c9c81c652f5a45b28b98998d378a0a0e7a6d..2e8ef42721e264e5f06149c21d7d6aa631d15552 100644 (file)
 
 #include <linux/module.h>
 #include <linux/string.h>
-
 #include "packet_history.h"
 
+/*
+ *     Transmitter History Routines
+ */
+struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
+{
+       struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
+       static const char dccp_tx_hist_mask[] = "tx_hist_%s";
+       char *slab_name;
+
+       if (hist == NULL)
+               goto out;
+
+       slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
+                           GFP_ATOMIC);
+       if (slab_name == NULL)
+               goto out_free_hist;
+
+       sprintf(slab_name, dccp_tx_hist_mask, name);
+       hist->dccptxh_slab = kmem_cache_create(slab_name,
+                                            sizeof(struct dccp_tx_hist_entry),
+                                              0, SLAB_HWCACHE_ALIGN,
+                                              NULL, NULL);
+       if (hist->dccptxh_slab == NULL)
+               goto out_free_slab_name;
+out:
+       return hist;
+out_free_slab_name:
+       kfree(slab_name);
+out_free_hist:
+       kfree(hist);
+       hist = NULL;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
+
+void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
+{
+       const char* name = kmem_cache_name(hist->dccptxh_slab);
+
+       kmem_cache_destroy(hist->dccptxh_slab);
+       kfree(name);
+       kfree(hist);
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
+
+struct dccp_tx_hist_entry *
+       dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
+{
+       struct dccp_tx_hist_entry *packet = NULL, *entry;
+
+       list_for_each_entry(entry, list, dccphtx_node)
+               if (entry->dccphtx_seqno == seq) {
+                       packet = entry;
+                       break;
+               }
+
+       return packet;
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
+
+void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
+{
+       struct dccp_tx_hist_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, list, dccphtx_node) {
+               list_del_init(&entry->dccphtx_node);
+               dccp_tx_hist_entry_delete(hist, entry);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
+
+void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
+                             struct list_head *list,
+                             struct dccp_tx_hist_entry *packet)
+{
+       struct dccp_tx_hist_entry *next;
+
+       list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
+               list_del_init(&packet->dccphtx_node);
+               dccp_tx_hist_entry_delete(hist, packet);
+       }
+}
+
+EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
+
+/*
+ *     Receiver History Routines
+ */
 struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
 {
        struct dccp_rx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
@@ -83,18 +174,24 @@ void dccp_rx_hist_delete(struct dccp_rx_hist *hist)
 
 EXPORT_SYMBOL_GPL(dccp_rx_hist_delete);
 
-void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
+int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
+                           u8 *ccval)
 {
-       struct dccp_rx_hist_entry *entry, *next;
+       struct dccp_rx_hist_entry *packet = NULL, *entry;
 
-       list_for_each_entry_safe(entry, next, list, dccphrx_node) {
-               list_del_init(&entry->dccphrx_node);
-               kmem_cache_free(hist->dccprxh_slab, entry);
-       }
-}
+       list_for_each_entry(entry, list, dccphrx_node)
+               if (entry->dccphrx_seqno == seq) {
+                       packet = entry;
+                       break;
+               }
 
-EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
+       if (packet)
+               *ccval = packet->dccphrx_ccval;
 
+       return packet != NULL;
+}
+
+EXPORT_SYMBOL_GPL(dccp_rx_hist_find_entry);
 struct dccp_rx_hist_entry *
                dccp_rx_hist_find_data_packet(const struct list_head *list)
 {
@@ -184,110 +281,18 @@ void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
 
 EXPORT_SYMBOL_GPL(dccp_rx_hist_add_packet);
 
-struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
-{
-       struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
-       static const char dccp_tx_hist_mask[] = "tx_hist_%s";
-       char *slab_name;
-
-       if (hist == NULL)
-               goto out;
-
-       slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
-                           GFP_ATOMIC);
-       if (slab_name == NULL)
-               goto out_free_hist;
-
-       sprintf(slab_name, dccp_tx_hist_mask, name);
-       hist->dccptxh_slab = kmem_cache_create(slab_name,
-                                            sizeof(struct dccp_tx_hist_entry),
-                                              0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
-       if (hist->dccptxh_slab == NULL)
-               goto out_free_slab_name;
-out:
-       return hist;
-out_free_slab_name:
-       kfree(slab_name);
-out_free_hist:
-       kfree(hist);
-       hist = NULL;
-       goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
-
-void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
-{
-       const char* name = kmem_cache_name(hist->dccptxh_slab);
-
-       kmem_cache_destroy(hist->dccptxh_slab);
-       kfree(name);
-       kfree(hist);
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
-
-struct dccp_tx_hist_entry *
-       dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq)
-{
-       struct dccp_tx_hist_entry *packet = NULL, *entry;
-
-       list_for_each_entry(entry, list, dccphtx_node)
-               if (entry->dccphtx_seqno == seq) {
-                       packet = entry;
-                       break;
-               }
-
-       return packet;
-}
-
-EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
-
-int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
-   u8 *ccval)
-{
-       struct dccp_rx_hist_entry *packet = NULL, *entry;
-
-       list_for_each_entry(entry, list, dccphrx_node)
-               if (entry->dccphrx_seqno == seq) {
-                       packet = entry;
-                       break;
-               }
-
-       if (packet)
-               *ccval = packet->dccphrx_ccval;
-
-       return packet != NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_rx_hist_find_entry);
-
-void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
-                             struct list_head *list,
-                             struct dccp_tx_hist_entry *packet)
+void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
 {
-       struct dccp_tx_hist_entry *next;
+       struct dccp_rx_hist_entry *entry, *next;
 
-       list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
-               list_del_init(&packet->dccphtx_node);
-               dccp_tx_hist_entry_delete(hist, packet);
+       list_for_each_entry_safe(entry, next, list, dccphrx_node) {
+               list_del_init(&entry->dccphrx_node);
+               kmem_cache_free(hist->dccprxh_slab, entry);
        }
 }
 
-EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
-
-void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
-{
-       struct dccp_tx_hist_entry *entry, *next;
-
-       list_for_each_entry_safe(entry, next, list, dccphtx_node) {
-               list_del_init(&entry->dccphtx_node);
-               dccp_tx_hist_entry_delete(hist, entry);
-       }
-}
+EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
 
-EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);
 
 MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
              "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
index 9a8bcf224aa73151a3775d2426524c38e1d169dd..1f960c19ea1bf0ca948403321efd30e09fb98de8 100644 (file)
 #define TFRC_WIN_COUNT_PER_RTT  4
 #define TFRC_WIN_COUNT_LIMIT   16
 
+/*
+ *     Transmitter History data structures and declarations
+ */
 struct dccp_tx_hist_entry {
        struct list_head dccphtx_node;
        u64              dccphtx_seqno:48,
-                        dccphtx_ccval:4,
                         dccphtx_sent:1;
        u32              dccphtx_rtt;
        struct timeval   dccphtx_tstamp;
 };
 
-struct dccp_rx_hist_entry {
-       struct list_head dccphrx_node;
-       u64              dccphrx_seqno:48,
-                        dccphrx_ccval:4,
-                        dccphrx_type:4;
-       u32              dccphrx_ndp; /* In fact it is from 8 to 24 bits */
-       struct timeval   dccphrx_tstamp;
-};
-
 struct dccp_tx_hist {
        struct kmem_cache *dccptxh_slab;
 };
 
 extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name);
-extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist);
-
-struct dccp_rx_hist {
-       struct kmem_cache *dccprxh_slab;
-};
-
-extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name);
-extern void dccp_rx_hist_delete(struct dccp_rx_hist *hist);
-extern struct dccp_rx_hist_entry *
-               dccp_rx_hist_find_data_packet(const struct list_head *list);
+extern void                dccp_tx_hist_delete(struct dccp_tx_hist *hist);
 
 static inline struct dccp_tx_hist_entry *
-               dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
-                                      const gfp_t prio)
+                       dccp_tx_hist_entry_new(struct dccp_tx_hist *hist,
+                                              const gfp_t prio)
 {
        struct dccp_tx_hist_entry *entry = kmem_cache_alloc(hist->dccptxh_slab,
                                                            prio);
@@ -96,18 +80,20 @@ static inline struct dccp_tx_hist_entry *
        return entry;
 }
 
-static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
-                                            struct dccp_tx_hist_entry *entry)
+static inline struct dccp_tx_hist_entry *
+                       dccp_tx_hist_head(struct list_head *list)
 {
-       if (entry != NULL)
-               kmem_cache_free(hist->dccptxh_slab, entry);
+       struct dccp_tx_hist_entry *head = NULL;
+
+       if (!list_empty(list))
+               head = list_entry(list->next, struct dccp_tx_hist_entry,
+                                 dccphtx_node);
+       return head;
 }
 
 extern struct dccp_tx_hist_entry *
                        dccp_tx_hist_find_entry(const struct list_head *list,
                                                const u64 seq);
-extern int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
-   u8 *ccval);
 
 static inline void dccp_tx_hist_add_entry(struct list_head *list,
                                          struct dccp_tx_hist_entry *entry)
@@ -115,30 +101,45 @@ static inline void dccp_tx_hist_add_entry(struct list_head *list,
        list_add(&entry->dccphtx_node, list);
 }
 
+static inline void dccp_tx_hist_entry_delete(struct dccp_tx_hist *hist,
+                                            struct dccp_tx_hist_entry *entry)
+{
+       if (entry != NULL)
+               kmem_cache_free(hist->dccptxh_slab, entry);
+}
+
+extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
+                              struct list_head *list);
+
 extern void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist,
                                     struct list_head *list,
                                     struct dccp_tx_hist_entry *next);
 
-extern void dccp_tx_hist_purge(struct dccp_tx_hist *hist,
-                              struct list_head *list);
+/*
+ *     Receiver History data structures and declarations
+ */
+struct dccp_rx_hist_entry {
+       struct list_head dccphrx_node;
+       u64              dccphrx_seqno:48,
+                        dccphrx_ccval:4,
+                        dccphrx_type:4;
+       u32              dccphrx_ndp; /* In fact it is from 8 to 24 bits */
+       struct timeval   dccphrx_tstamp;
+};
 
-static inline struct dccp_tx_hist_entry *
-               dccp_tx_hist_head(struct list_head *list)
-{
-       struct dccp_tx_hist_entry *head = NULL;
+struct dccp_rx_hist {
+       struct kmem_cache *dccprxh_slab;
+};
 
-       if (!list_empty(list))
-               head = list_entry(list->next, struct dccp_tx_hist_entry,
-                                 dccphtx_node);
-       return head;
-}
+extern struct dccp_rx_hist *dccp_rx_hist_new(const char *name);
+extern void            dccp_rx_hist_delete(struct dccp_rx_hist *hist);
 
 static inline struct dccp_rx_hist_entry *
-                    dccp_rx_hist_entry_new(struct dccp_rx_hist *hist,
-                                           const struct sock *sk, 
-                                           const u32 ndp, 
-                                           const struct sk_buff *skb,
-                                           const gfp_t prio)
+                       dccp_rx_hist_entry_new(struct dccp_rx_hist *hist,
+                                              const struct sock *sk,
+                                              const u32 ndp,
+                                              const struct sk_buff *skb,
+                                              const gfp_t prio)
 {
        struct dccp_rx_hist_entry *entry = kmem_cache_alloc(hist->dccprxh_slab,
                                                            prio);
@@ -156,18 +157,8 @@ static inline struct dccp_rx_hist_entry *
        return entry;
 }
 
-static inline void dccp_rx_hist_entry_delete(struct dccp_rx_hist *hist,
-                                            struct dccp_rx_hist_entry *entry)
-{
-       if (entry != NULL)
-               kmem_cache_free(hist->dccprxh_slab, entry);
-}
-
-extern void dccp_rx_hist_purge(struct dccp_rx_hist *hist,
-                              struct list_head *list);
-
 static inline struct dccp_rx_hist_entry *
-               dccp_rx_hist_head(struct list_head *list)
+                       dccp_rx_hist_head(struct list_head *list)
 {
        struct dccp_rx_hist_entry *head = NULL;
 
@@ -177,6 +168,27 @@ static inline struct dccp_rx_hist_entry *
        return head;
 }
 
+extern int dccp_rx_hist_find_entry(const struct list_head *list, const u64 seq,
+                                  u8 *ccval);
+extern struct dccp_rx_hist_entry *
+               dccp_rx_hist_find_data_packet(const struct list_head *list);
+
+extern void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
+                                   struct list_head *rx_list,
+                                   struct list_head *li_list,
+                                   struct dccp_rx_hist_entry *packet,
+                                   u64 nonloss_seqno);
+
+static inline void dccp_rx_hist_entry_delete(struct dccp_rx_hist *hist,
+                                            struct dccp_rx_hist_entry *entry)
+{
+       if (entry != NULL)
+               kmem_cache_free(hist->dccprxh_slab, entry);
+}
+
+extern void dccp_rx_hist_purge(struct dccp_rx_hist *hist,
+                              struct list_head *list);
+
 static inline int
        dccp_rx_hist_entry_data_packet(const struct dccp_rx_hist_entry *entry)
 {
@@ -184,12 +196,6 @@ static inline int
               entry->dccphrx_type == DCCP_PKT_DATAACK;
 }
 
-extern void dccp_rx_hist_add_packet(struct dccp_rx_hist *hist,
-                                  struct list_head *rx_list,
-                                  struct list_head *li_list,
-                                  struct dccp_rx_hist_entry *packet,
-                                  u64 nonloss_seqno);
-
 extern u64 dccp_rx_hist_detect_loss(struct list_head *rx_list,
                                    struct list_head *li_list, u8 *win_loss);
 
index 45f30f59ea2ab134d741bf22ef1dc3330d5aee05..faf5f7e219e36a85ecdfdf182e81ba8e6b7ef4af 100644 (file)
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  */
-
 #include <linux/types.h>
+#include <asm/div64.h>
+
+/* integer-arithmetic divisions of type (a * 1000000)/b */
+static inline u64 scaled_div(u64 a, u32 b)
+{
+       BUG_ON(b==0);
+       a *= 1000000;
+       do_div(a, b);
+       return a;
+}
+
+static inline u32 scaled_div32(u64 a, u32 b)
+{
+       u64 result = scaled_div(a, b);
+
+       if (result > UINT_MAX) {
+               DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U",
+                         (unsigned long long)a, b);
+               return UINT_MAX;
+       }
+       return result;
+}
 
 extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
 extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
index ddac2c511e2f288014ad1650881586b514472eec..90009fd77e158f03e3e1a4002a23be34d0bd7e01 100644 (file)
@@ -13,7 +13,6 @@
  */
 
 #include <linux/module.h>
-#include <asm/div64.h>
 #include "../../dccp.h"
 #include "tfrc.h"
 
@@ -616,15 +615,12 @@ static inline u32 tfrc_binsearch(u32 fval, u8 small)
  *  @R: RTT                  scaled by 1000000   (i.e., microseconds)
  *  @p: loss ratio estimate  scaled by 1000000
  *  Returns X_calc           in bytes per second (not scaled).
- *
- * Note: DO NOT alter this code unless you run test cases against it,
- *       as the code has been optimized to stop underflow/overflow.
  */
 u32 tfrc_calc_x(u16 s, u32 R, u32 p)
 {
-       int index;
+       u16 index;
        u32 f;
-       u64 tmp1, tmp2;
+       u64 result;
 
        /* check against invalid parameters and divide-by-zero   */
        BUG_ON(p >  1000000);           /* p must not exceed 100%   */
@@ -650,15 +646,17 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
                f = tfrc_calc_x_lookup[index][0];
        }
 
-       /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
-        * and R are both scaled by 1000000, we need to multiply by 1000000^2.
-        * ==> DO NOT alter this unless you test against overflow on 32 bit   */
-       tmp1 = ((u64)s * 100000000);
-       tmp2 = ((u64)R * (u64)f);
-       do_div(tmp2, 10000);
-       do_div(tmp1, tmp2); 
-
-       return (u32)tmp1; 
+       /*
+        * Compute X = s/(R*f(p)) in bytes per second.
+        * Since f(p) and R are both scaled by 1000000, we need to multiply by
+        * 1000000^2. To avoid overflow, the result is computed in two stages.
+        * This works under almost all reasonable operational conditions, for a
+        * wide range of parameters. Yet, should some strange combination of
+        * parameters result in overflow, the use of scaled_div32 will catch
+        * this and return UINT_MAX - which is a logically adequate consequence.
+        */
+       result = scaled_div(s, R);
+       return scaled_div32(result, f);
 }
 
 EXPORT_SYMBOL_GPL(tfrc_calc_x);
index 68886986c8e4006165ff3fffc3f6c7138c4e5546..a0900bf98e6bbaf223f6cc3a02b500772ecc1781 100644 (file)
@@ -80,8 +80,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 
 #define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
 
-#define DCCP_XMIT_TIMEO 30000 /* Time/msecs for blocking transmit per packet */
-
 /* sysctl variables for DCCP */
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
@@ -434,6 +432,7 @@ static inline void timeval_sub_usecs(struct timeval *tv,
                tv->tv_sec--;
                tv->tv_usec += USEC_PER_SEC;
        }
+       DCCP_BUG_ON(tv->tv_sec < 0);
 }
 
 #ifdef CONFIG_SYSCTL
index 4dc487f27a1fff1a0d8f01bb8146a337f01ec376..95b6927ec6530eef17fab12cc5784d101fa7ded9 100644 (file)
@@ -329,7 +329,7 @@ static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
        switch (type) {
        case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break;
        case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break;
-       default:             DCCP_WARN("invalid type %d\n", type); return;
+       default:             DCCP_WARN("invalid type %d\n", type); return;
 
        }
        opt->dccpop_feat = feature;
@@ -427,7 +427,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
        switch (type) {
        case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
        case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-       default:              DCCP_WARN("invalid type %d\n", type);
+       default:              DCCP_WARN("invalid type %d\n", type);
                              return 1;
 
        }
@@ -610,7 +610,7 @@ const char *dccp_feat_typename(const u8 type)
        case DCCPO_CHANGE_R:  return("ChangeR");
        case DCCPO_CONFIRM_R: return("ConfirmR");
        /* the following case must not appear in feature negotation  */
-       default:              dccp_pr_debug("unknown type %d [BUG!]\n", type);
+       default:              dccp_pr_debug("unknown type %d [BUG!]\n", type);
        }
        return NULL;
 }
index 7371a2f3acf4f2826f4b47124a56fc3d0879af37..565bc80557ceb79139ea96c930652def3a56237d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  net/dccp/input.c
- * 
+ *
  *  An implementation of the DCCP protocol
  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
@@ -82,7 +82,7 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
         *        Otherwise,
         *           Drop packet and return
         */
-       if (dh->dccph_type == DCCP_PKT_SYNC || 
+       if (dh->dccph_type == DCCP_PKT_SYNC ||
            dh->dccph_type == DCCP_PKT_SYNCACK) {
                if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
                              dp->dccps_awl, dp->dccps_awh) &&
@@ -185,8 +185,8 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
                dccp_rcv_close(sk, skb);
                return 0;
        case DCCP_PKT_REQUEST:
-               /* Step 7 
-                *   or (S.is_server and P.type == Response)
+               /* Step 7
+                *   or (S.is_server and P.type == Response)
                 *   or (S.is_client and P.type == Request)
                 *   or (S.state >= OPEN and P.type == Request
                 *      and P.seqno >= S.OSR)
@@ -248,8 +248,18 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
                            DCCP_ACKVEC_STATE_RECEIVED))
                goto discard;
 
-       ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
-       ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+       /*
+        * Deliver to the CCID module in charge.
+        * FIXME: Currently DCCP operates one-directional only, i.e. a listening
+        *        server is not at the same time a connecting client. There is
+        *        not much sense in delivering to both rx/tx sides at the moment
+        *        (only one is active at a time); when moving to bidirectional
+        *        service, this needs to be revised.
+        */
+       if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+               ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+       else
+               ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
 
        return __dccp_rcv_established(sk, skb, dh, len);
 discard:
@@ -264,7 +274,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                                               const struct dccp_hdr *dh,
                                               const unsigned len)
 {
-       /* 
+       /*
         *  Step 4: Prepare sequence numbers in REQUEST
         *     If S.state == REQUEST,
         *        If (P.type == Response or P.type == Reset)
@@ -332,7 +342,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                 *            from the Response * /
                 *        S.state := PARTOPEN
                 *        Set PARTOPEN timer
-                *        Continue with S.state == PARTOPEN
+                *        Continue with S.state == PARTOPEN
                 *        / * Step 12 will send the Ack completing the
                 *            three-way handshake * /
                 */
@@ -363,7 +373,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                         */
                        __kfree_skb(skb);
                        return 0;
-               } 
+               }
                dccp_send_ack(sk);
                return -1;
        }
@@ -371,7 +381,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 out_invalid_packet:
        /* dccp_v4_do_rcv will send a reset */
        DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
-       return 1; 
+       return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -478,14 +488,17 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
                        dccp_event_ack_recv(sk, skb);
 
-               if (dccp_msk(sk)->dccpms_send_ack_vector &&
+               if (dccp_msk(sk)->dccpms_send_ack_vector &&
                    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-                                   DCCP_SKB_CB(skb)->dccpd_seq,
-                                   DCCP_ACKVEC_STATE_RECEIVED))
-                       goto discard;
+                                   DCCP_SKB_CB(skb)->dccpd_seq,
+                                   DCCP_ACKVEC_STATE_RECEIVED))
+                       goto discard;
 
-               ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
-               ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
+               /* XXX see the comments in dccp_rcv_established about this */
+               if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+                       ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+               else
+                       ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
        }
 
        /*
@@ -567,7 +580,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                }
        }
 
-       if (!queued) { 
+       if (!queued) {
 discard:
                __kfree_skb(skb);
        }
index ff81679c9f1743970455cf387141ca4fb50700d2..90c74b4adb7396443a36d8124633e2d22abd5551 100644 (file)
@@ -157,7 +157,7 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
        /* We don't check in the destentry if pmtu discovery is forbidden
         * on this route. We just assume that no packet_to_big packets
         * are send back when pmtu discovery is not active.
-        * There is a small race when the user changes this flag in the
+        * There is a small race when the user changes this flag in the
         * route, but I think that's acceptable.
         */
        if ((dst = __sk_dst_check(sk, 0)) == NULL)
@@ -467,7 +467,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
                            .uli_u = { .ports =
                                       { .sport = dccp_hdr(skb)->dccph_dport,
                                         .dport = dccp_hdr(skb)->dccph_sport }
-                                    }
+                                    }
                          };
 
        security_skb_classify_flow(skb, &fl);
@@ -595,7 +595,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        struct inet_request_sock *ireq;
        struct request_sock *req;
        struct dccp_request_sock *dreq;
-       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
+       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
 
@@ -609,7 +609,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        if (dccp_bad_service_code(sk, service)) {
                reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
                goto drop;
-       }
+       }
        /*
         * TW buckets are converted to open requests without
         * limitations, they conserve resources and peer is
@@ -644,7 +644,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        ireq->rmt_addr = skb->nh.iph->saddr;
        ireq->opt       = NULL;
 
-       /* 
+       /*
         * Step 3: Process LISTEN state
         *
         * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
@@ -846,15 +846,15 @@ static int dccp_v4_rcv(struct sk_buff *skb)
        }
 
        /* Step 2:
-        *      Look up flow ID in table and get corresponding socket */
+        *      Look up flow ID in table and get corresponding socket */
        sk = __inet_lookup(&dccp_hashinfo,
                           skb->nh.iph->saddr, dh->dccph_sport,
                           skb->nh.iph->daddr, dh->dccph_dport,
                           inet_iif(skb));
 
-       /* 
+       /*
         * Step 2:
-        *      If no socket ...
+        *      If no socket ...
         */
        if (sk == NULL) {
                dccp_pr_debug("failed to look up flow ID in table and "
@@ -862,9 +862,9 @@ static int dccp_v4_rcv(struct sk_buff *skb)
                goto no_dccp_socket;
        }
 
-       /* 
+       /*
         * Step 2:
-        *      ... or S.state == TIMEWAIT,
+        *      ... or S.state == TIMEWAIT,
         *              Generate Reset(No Connection) unless P.type == Reset
         *              Drop packet and return
         */
@@ -876,8 +876,8 @@ static int dccp_v4_rcv(struct sk_buff *skb)
 
        /*
         * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
-        *      o if MinCsCov = 0, only packets with CsCov = 0 are accepted
-        *      o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
+        *      o if MinCsCov = 0, only packets with CsCov = 0 are accepted
+        *      o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
         */
        min_cov = dccp_sk(sk)->dccps_pcrlen;
        if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov))  {
@@ -900,7 +900,7 @@ no_dccp_socket:
                goto discard_it;
        /*
         * Step 2:
-        *      If no socket ...
+        *      If no socket ...
         *              Generate Reset(No Connection) unless P.type == Reset
         *              Drop packet and return
         */
index c7aaa2574f52d3036f28dcb8ba896e914800406b..6b91a9dd04111298c96127ea49e18d864602e9f9 100644 (file)
@@ -77,7 +77,7 @@ static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
 }
 
 static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-                                                 __be16 sport, __be16 dport   )
+                                                 __be16 sport, __be16 dport   )
 {
        return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);
 }
@@ -329,7 +329,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
                        GFP_ATOMIC);
        if (skb == NULL)
-               return;
+               return;
 
        skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
 
@@ -353,7 +353,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
 
        dccp_csum_outgoing(skb);
        dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
-                                                     &rxskb->nh.ipv6h->daddr);
+                                                     &rxskb->nh.ipv6h->daddr);
 
        memset(&fl, 0, sizeof(fl));
        ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
@@ -424,7 +424,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        struct dccp_request_sock *dreq;
        struct inet6_request_sock *ireq6;
        struct ipv6_pinfo *np = inet6_sk(sk);
-       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
+       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
 
@@ -437,7 +437,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        if (dccp_bad_service_code(sk, service)) {
                reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
                goto drop;
-       }
+       }
        /*
         * There are no SYN attacks on IPv6, yet...
         */
@@ -787,7 +787,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                 * otherwise we just shortcircuit this and continue with
                 * the new socket..
                 */
-               if (nsk != sk) {
+               if (nsk != sk) {
                        if (dccp_child_process(sk, nsk, skb))
                                goto reset;
                        if (opt_skb != NULL)
@@ -843,14 +843,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
                DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
 
        /* Step 2:
-        *      Look up flow ID in table and get corresponding socket */
+        *      Look up flow ID in table and get corresponding socket */
        sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
                            dh->dccph_sport,
                            &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
                            inet6_iif(skb));
        /*
         * Step 2:
-        *      If no socket ...
+        *      If no socket ...
         */
        if (sk == NULL) {
                dccp_pr_debug("failed to look up flow ID in table and "
@@ -860,7 +860,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
 
        /*
         * Step 2:
-        *      ... or S.state == TIMEWAIT,
+        *      ... or S.state == TIMEWAIT,
         *              Generate Reset(No Connection) unless P.type == Reset
         *              Drop packet and return
         */
@@ -872,8 +872,8 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
 
        /*
         * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
-        *      o if MinCsCov = 0, only packets with CsCov = 0 are accepted
-        *      o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
+        *      o if MinCsCov = 0, only packets with CsCov = 0 are accepted
+        *      o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
         */
        min_cov = dccp_sk(sk)->dccps_pcrlen;
        if (dh->dccph_cscov  &&  (min_cov == 0 || dh->dccph_cscov < min_cov))  {
@@ -893,7 +893,7 @@ no_dccp_socket:
                goto discard_it;
        /*
         * Step 2:
-        *      If no socket ...
+        *      If no socket ...
         *              Generate Reset(No Connection) unless P.type == Reset
         *              Drop packet and return
         */
index 4c9e26775f72ddad7a1c0f9f53c7c9656247e91f..6656bb497c7bde44aa37520cb5e65781b24179a6 100644 (file)
@@ -182,7 +182,7 @@ out_free:
 
 EXPORT_SYMBOL_GPL(dccp_create_openreq_child);
 
-/* 
+/*
  * Process an incoming packet for RESPOND sockets represented
  * as an request_sock.
  */
index f398b43bc055fef04bd4f0fa72adaa06d73ca7be..c03ba61eb6da3c37a1bd225a24b566fdd2e89434 100644 (file)
@@ -557,11 +557,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
                        return -1;
                dp->dccps_hc_rx_insert_options = 0;
        }
-       if (dp->dccps_hc_tx_insert_options) {
-               if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb))
-                       return -1;
-               dp->dccps_hc_tx_insert_options = 0;
-       }
 
        /* Feature negotiation */
        /* Data packets can't do feat negotiation */
index 400c30b6fcae4d1e0357188d2081e60d06072e55..824569659083825304d8c1d38413cbc186466014 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  net/dccp/output.c
- * 
+ *
  *  An implementation of the DCCP protocol
  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
@@ -175,14 +175,12 @@ void dccp_write_space(struct sock *sk)
 /**
  * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
  * @sk: socket to wait for
- * @timeo: for how long
  */
-static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
-                             long *timeo)
+static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        DEFINE_WAIT(wait);
-       long delay;
+       unsigned long delay;
        int rc;
 
        while (1) {
@@ -190,8 +188,6 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
 
                if (sk->sk_err)
                        goto do_error;
-               if (!*timeo)
-                       goto do_nonblock;
                if (signal_pending(current))
                        goto do_interrupted;
 
@@ -199,12 +195,9 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
                if (rc <= 0)
                        break;
                delay = msecs_to_jiffies(rc);
-               if (delay > *timeo || delay < 0)
-                       goto do_nonblock;
-
                sk->sk_write_pending++;
                release_sock(sk);
-               *timeo -= schedule_timeout(delay);
+               schedule_timeout(delay);
                lock_sock(sk);
                sk->sk_write_pending--;
        }
@@ -215,11 +208,8 @@ out:
 do_error:
        rc = -EPIPE;
        goto out;
-do_nonblock:
-       rc = -EAGAIN;
-       goto out;
 do_interrupted:
-       rc = sock_intr_errno(*timeo);
+       rc = -EINTR;
        goto out;
 }
 
@@ -240,8 +230,6 @@ void dccp_write_xmit(struct sock *sk, int block)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        struct sk_buff *skb;
-       long timeo = DCCP_XMIT_TIMEO;   /* If a packet is taking longer than
-                                          this we have other issues */
 
        while ((skb = skb_peek(&sk->sk_write_queue))) {
                int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
@@ -251,11 +239,9 @@ void dccp_write_xmit(struct sock *sk, int block)
                                sk_reset_timer(sk, &dp->dccps_xmit_timer,
                                                msecs_to_jiffies(err)+jiffies);
                                break;
-                       } else {
-                               err = dccp_wait_for_ccid(sk, skb, &timeo);
-                               timeo = DCCP_XMIT_TIMEO;
-                       }
-                       if (err)
+                       } else
+                               err = dccp_wait_for_ccid(sk, skb);
+                       if (err && err != -EINTR)
                                DCCP_BUG("err=%d after dccp_wait_for_ccid", err);
                }
 
@@ -281,8 +267,10 @@ void dccp_write_xmit(struct sock *sk, int block)
                        if (err)
                                DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
                                         err);
-               } else
+               } else {
+                       dccp_pr_debug("packet discarded\n");
                        kfree(skb);
+               }
        }
 }
 
@@ -350,7 +338,6 @@ EXPORT_SYMBOL_GPL(dccp_make_response);
 
 static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
                                       const enum dccp_reset_codes code)
-                                  
 {
        struct dccp_hdr *dh;
        struct dccp_sock *dp = dccp_sk(sk);
@@ -431,14 +418,14 @@ static inline void dccp_connect_init(struct sock *sk)
        
        dccp_sync_mss(sk, dst_mtu(dst));
 
-       /*
+       /*
         * SWL and AWL are initially adjusted so that they are not less than
         * the initial Sequence Numbers received and sent, respectively:
         *      SWL := max(GSR + 1 - floor(W/4), ISR),
         *      AWL := max(GSS - W' + 1, ISS).
         * These adjustments MUST be applied only at the beginning of the
         * connection.
-        */
+        */
        dccp_update_gss(sk, dp->dccps_iss);
        dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
 
index 5ec47d9ee447e226a482010a13c3d97aa773cd26..63b3fa20e14bbb718d3baa9a7a16c2bcb1a503bd 100644 (file)
@@ -196,7 +196,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
                                                      sk, GFP_KERNEL);
                dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
                                                      sk, GFP_KERNEL);
-               if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
+               if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
                             dp->dccps_hc_tx_ccid == NULL)) {
                        ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
                        ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
@@ -390,7 +390,7 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
        struct dccp_sock *dp = dccp_sk(sk);
        struct dccp_service_list *sl = NULL;
 
-       if (service == DCCP_SERVICE_INVALID_VALUE || 
+       if (service == DCCP_SERVICE_INVALID_VALUE ||
            optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
                return -EINVAL;
 
@@ -830,7 +830,7 @@ EXPORT_SYMBOL_GPL(inet_dccp_listen);
 static const unsigned char dccp_new_state[] = {
        /* current state:   new state:      action:     */
        [0]               = DCCP_CLOSED,
-       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
        [DCCP_REQUESTING] = DCCP_CLOSED,
        [DCCP_PARTOPEN]   = DCCP_CLOSING | DCCP_ACTION_FIN,
        [DCCP_LISTEN]     = DCCP_CLOSED,
index e8f519e7f481133f7b3b50c5d317e7e7f3628cd3..e5348f369c60a09055e4f7b464d9e3520eb95f35 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  net/dccp/timer.c
- * 
+ *
  *  An implementation of the DCCP protocol
  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
@@ -102,13 +102,13 @@ static void dccp_retransmit_timer(struct sock *sk)
         * sk->sk_send_head has to have one skb with
         * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
         * packet types. The only packets eligible for retransmission are:
-        *      -- Requests in client-REQUEST  state (sec. 8.1.1)
-        *      -- Acks     in client-PARTOPEN state (sec. 8.1.5)
-        *      -- CloseReq in server-CLOSEREQ state (sec. 8.3)
-        *      -- Close    in   node-CLOSING  state (sec. 8.3)                */
+        *      -- Requests in client-REQUEST  state (sec. 8.1.1)
+        *      -- Acks     in client-PARTOPEN state (sec. 8.1.5)
+        *      -- CloseReq in server-CLOSEREQ state (sec. 8.3)
+        *      -- Close    in   node-CLOSING  state (sec. 8.3)                */
        BUG_TRAP(sk->sk_send_head != NULL);
 
-       /* 
+       /*
         * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
         * sent, no need to retransmit, this sock is dead.
         */
@@ -200,7 +200,7 @@ static void dccp_keepalive_timer(unsigned long data)
        /* Only process if socket is not in use. */
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
-               /* Try again later. */ 
+               /* Try again later. */
                inet_csk_reset_keepalive_timer(sk, HZ / 20);
                goto out;
        }
index 0b9d4c9551543df799890cca4887f4d6adeec00f..fc6f3c023a543fdb30cca938856de595eb38838f 100644 (file)
@@ -167,8 +167,7 @@ static int dn_forwarding_proc(ctl_table *, int, struct file *,
                        void __user *, size_t *, loff_t *);
 static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
                        void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen,
-                       void **context);
+                       void __user *newval, size_t newlen);
 
 static struct dn_dev_sysctl_table {
        struct ctl_table_header *sysctl_header;
@@ -347,8 +346,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
 
 static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
                        void __user *oldval, size_t __user *oldlenp,
-                       void __user *newval, size_t newlen,
-                       void **context)
+                       void __user *newval, size_t newlen)
 {
 #ifdef CONFIG_DECNET_ROUTER
        struct net_device *dev = table->extra1;
index e246f054f368f692a13ed7cee98db0abbf971645..a4065eb1341eba834db319faec739d8a46e8c93f 100644 (file)
@@ -134,8 +134,7 @@ static int parse_addr(__le16 *addr, char *str)
 
 static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
                                void __user *oldval, size_t __user *oldlenp,
-                               void __user *newval, size_t newlen,
-                               void **context)
+                               void __user *newval, size_t newlen)
 {
        size_t len;
        __le16 addr;
@@ -220,8 +219,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
 
 static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
                                void __user *oldval, size_t __user *oldlenp,
-                               void __user *newval, size_t newlen,
-                               void **context)
+                               void __user *newval, size_t newlen)
 {
        size_t len;
        struct net_device *dev;
index eec1a1dd91da255714c88f8081ac2d28cb94956f..e3f37fdda65f6d34cee54693640bad4b5543774f 100644 (file)
@@ -438,7 +438,7 @@ ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
 
        spin_lock_irqsave(&mac->lock, flags);
        mac->associnfo.associating = 1;
-       schedule_work(&mac->associnfo.work);
+       schedule_delayed_work(&mac->associnfo.work, 0);
        spin_unlock_irqrestore(&mac->lock, flags);
 }
 
index 2fd899160f8590d59076e54b2fad98389dcb7d96..84bed40273adc1413bb6480257f4a1adca712e28 100644 (file)
@@ -1303,8 +1303,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
 
 int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
                                  void __user *oldval, size_t __user *oldlenp,
-                                 void __user *newval, size_t newlen, 
-                                 void **context)
+                                 void __user *newval, size_t newlen)
 {
        int *valp = table->data;
        int new;
index 91a075edd68e379fc8fcad685ac1ecd53c4801b7..7ea2d981a9328490df6dc684b6f1768fe0304f3d 100644 (file)
@@ -657,7 +657,7 @@ static void sync_master_loop(void)
                if (stop_master_sync)
                        break;
 
-               ssleep(1);
+               msleep_interruptible(1000);
        }
 
        /* clean up the sync_buff queue */
@@ -714,7 +714,7 @@ static void sync_backup_loop(void)
                if (stop_backup_sync)
                        break;
 
-               ssleep(1);
+               msleep_interruptible(1000);
        }
 
        /* release the sending multicast socket */
@@ -826,7 +826,7 @@ static int fork_sync_thread(void *startup)
        if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) {
                IP_VS_ERR("could not create sync_thread due to %d... "
                          "retrying.\n", pid);
-               ssleep(1);
+               msleep_interruptible(1000);
                goto repeat;
        }
 
@@ -849,10 +849,12 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 
        ip_vs_sync_state |= state;
        if (state == IP_VS_STATE_MASTER) {
-               strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, sizeof(ip_vs_master_mcast_ifn));
+               strlcpy(ip_vs_master_mcast_ifn, mcast_ifn,
+                       sizeof(ip_vs_master_mcast_ifn));
                ip_vs_master_syncid = syncid;
        } else {
-               strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, sizeof(ip_vs_backup_mcast_ifn));
+               strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn,
+                       sizeof(ip_vs_backup_mcast_ifn));
                ip_vs_backup_syncid = syncid;
        }
 
@@ -860,7 +862,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
        if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) {
                IP_VS_ERR("could not create fork_sync_thread due to %d... "
                          "retrying.\n", pid);
-               ssleep(1);
+               msleep_interruptible(1000);
                goto repeat;
        }
 
@@ -880,7 +882,8 @@ int stop_sync_thread(int state)
 
        IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, current->pid);
        IP_VS_INFO("stopping sync thread %d ...\n",
-                  (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid);
+                  (state == IP_VS_STATE_MASTER) ?
+                  sync_master_pid : sync_backup_pid);
 
        __set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&stop_sync_wait, &wait);
index 11c167118e87fa87ecfd7898a6190c06fd24d7a0..1aaff0a2e09854604aca047e8f555170ae37427b 100644 (file)
@@ -2872,8 +2872,7 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
                                                void __user *oldval,
                                                size_t __user *oldlenp,
                                                void __user *newval,
-                                               size_t newlen,
-                                               void **context)
+                                               size_t newlen)
 {
        int delay;
        if (newlen != sizeof(int))
index dfcf47f10f88b94318a33fa36768d012606afba1..fabf69a9108ca6f6d42f58c3eca46b30f1ffae6b 100644 (file)
@@ -51,8 +51,7 @@ int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
 static int ipv4_sysctl_forward_strategy(ctl_table *table,
                         int __user *name, int nlen,
                         void __user *oldval, size_t __user *oldlenp,
-                        void __user *newval, size_t newlen, 
-                        void **context)
+                        void __user *newval, size_t newlen)
 {
        int *valp = table->data;
        int new;
@@ -111,8 +110,7 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file *
 static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
                                         int nlen, void __user *oldval,
                                         size_t __user *oldlenp,
-                                        void __user *newval, size_t newlen,
-                                        void **context)
+                                        void __user *newval, size_t newlen)
 {
        char val[TCP_CA_NAME_MAX];
        ctl_table tbl = {
@@ -122,8 +120,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
        int ret;
 
        tcp_get_default_congestion_control(val);
-       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
-                           context);
+       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
        if (ret == 0 && newval && newlen)
                ret = tcp_set_default_congestion_control(val);
        return ret;
@@ -169,8 +166,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl,
 static int strategy_allowed_congestion_control(ctl_table *table, int __user *name,
                                               int nlen, void __user *oldval,
                                               size_t __user *oldlenp,
-                                              void __user *newval, size_t newlen,
-                                              void **context)
+                                              void __user *newval,
+                                              size_t newlen)
 {
        ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX };
        int ret;
@@ -180,8 +177,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
                return -ENOMEM;
 
        tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
-       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
-                           context);
+       ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
        if (ret == 0 && newval && newlen)
                ret = tcp_set_allowed_congestion_control(tbl.data);
        kfree(tbl.data);
index a5e8d207a51b72eb1c3ae4a65bd1f825f4d7100f..9b0a906431510d8acda8501bc0f40e42b8869a43 100644 (file)
@@ -3656,8 +3656,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
                                            int __user *name, int nlen,
                                            void __user *oldval,
                                            size_t __user *oldlenp,
-                                           void __user *newval, size_t newlen,
-                                           void **context)
+                                           void __user *newval, size_t newlen)
 {
        int *valp = table->data;
        int new;
index 56ea92837307cef89e2f844b1a8a1945401a7676..6a9f616de37d32cebdd0eca952b24cef5620ecf9 100644 (file)
@@ -1667,8 +1667,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
 static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
                                        int nlen, void __user *oldval,
                                        size_t __user *oldlenp,
-                                       void __user *newval, size_t newlen,
-                                       void **context)
+                                       void __user *newval, size_t newlen)
 {
        struct net_device *dev = ctl->extra1;
        struct inet6_dev *idev;
@@ -1681,14 +1680,12 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
        switch (ctl->ctl_name) {
        case NET_NEIGH_REACHABLE_TIME:
                ret = sysctl_jiffies(ctl, name, nlen,
-                                    oldval, oldlenp, newval, newlen,
-                                    context);
+                                    oldval, oldlenp, newval, newlen);
                break;
        case NET_NEIGH_RETRANS_TIME_MS:
        case NET_NEIGH_REACHABLE_TIME_MS:
                 ret = sysctl_ms_jiffies(ctl, name, nlen,
-                                        oldval, oldlenp, newval, newlen,
-                                        context);
+                                        oldval, oldlenp, newval, newlen);
                 break;
        default:
                ret = 0;
index 4f5ff19b992b1f8a8db6f28a96cbace409db3baa..f01f8c072852b5b7b1871d9955170346b55a0e5a 100644 (file)
@@ -56,6 +56,9 @@ endef
 # gcc support functions
 # See documentation in Documentation/kbuild/makefiles.txt
 
+# output directory for tests below
+TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
+
 # as-option
 # Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
 
@@ -66,9 +69,11 @@ as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
 # as-instr
 # Usage: cflags-y += $(call as-instr, instr, option1, option2)
 
-as-instr = $(shell if echo -e "$(1)" | $(AS) >/dev/null 2>&1 -W -Z -o astest$$$$.out ; \
-                  then echo "$(2)"; else echo "$(3)"; fi; \
-                  rm -f astest$$$$.out)
+as-instr = $(shell if echo -e "$(1)" | \
+                     $(CC) $(AFLAGS) -c -xassembler - \
+                           -o $(TMPOUT)astest$$$$.out > /dev/null 2>&1; \
+                  then rm $(TMPOUT)astest$$$$.out; echo "$(2)"; \
+                  else echo "$(3)"; fi)
 
 # cc-option
 # Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
@@ -97,10 +102,10 @@ cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
 
 # ld-option
 # Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both)
-ld-option = $(shell if $(CC) $(1) \
-                            -nostdlib -o ldtest$$$$.out -xc /dev/null \
-             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi; \
-            rm -f ldtest$$$$.out)
+ld-option = $(shell if $(CC) $(1) -nostdlib -xc /dev/null \
+                            -o $(TMPOUT)ldtest$$$$.out > /dev/null 2>&1; \
+             then rm $(TMPOUT)ldtest$$$$.out; echo "$(1)"; \
+             else echo "$(2)"; fi)
 
 ###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
index 3753416eb9b98834e2d3645a761de7f2e595717c..65fb5e8ea9419ba1dc984c728d2614721f7bbf9b 100644 (file)
@@ -1734,7 +1734,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                j++;
                i = j * __NFDBITS;
                fdt = files_fdtable(files);
-               if (i >= fdt->max_fds || i >= fdt->max_fdset)
+               if (i >= fdt->max_fds)
                        break;
                set = fdt->open_fds->fds_bits[j];
                if (!set)